@caddis/cli 0.3.0 → 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 (244) hide show
  1. package/bundles/antigravity-plugin/agents/knowledge-transfer.md +17 -32
  2. package/bundles/antigravity-plugin/caddis_statusline.py +25 -3
  3. package/bundles/antigravity-plugin/guard_agy.py +41 -9
  4. package/bundles/antigravity-plugin/plugin.json +1 -1
  5. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +73 -3
  6. package/bundles/antigravity-plugin/scripts/caddis_statusline.py +25 -3
  7. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +1 -1
  8. package/bundles/antigravity-plugin/scripts/claudster_config.py +0 -5
  9. package/bundles/antigravity-plugin/scripts/hook_log.py +1 -1
  10. package/bundles/antigravity-plugin/scripts/new-machine.ps1 +170 -0
  11. package/bundles/antigravity-plugin/scripts/oss_ask.py +1 -1
  12. package/bundles/antigravity-plugin/scripts/oss_model.py +10 -2
  13. package/bundles/antigravity-plugin/scripts/oss_review.py +1 -1
  14. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +42 -10
  15. package/bundles/antigravity-plugin/session_end_agy.py +31 -6
  16. package/bundles/antigravity-plugin/skills/_registry.md +1 -0
  17. package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +44 -0
  18. package/bundles/antigravity-plugin/skills/code-review/SKILL.md +11 -0
  19. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +21 -0
  20. package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +11 -0
  21. package/bundles/antigravity-plugin/skills/implement/SKILL.md +36 -0
  22. package/bundles/antigravity-plugin/skills/safe-cleanup/SKILL.md +186 -0
  23. package/bundles/antigravity-plugin/skills/security-review/SKILL.md +9 -0
  24. package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +31 -0
  25. package/bundles/antigravity-plugin/warm_start_agy.py +96 -9
  26. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  27. package/bundles/antigravity-plugin-extras/skills/_registry.md +1 -0
  28. package/bundles/antigravity-plugin-extras/skills/safe-cleanup/SKILL.md +186 -0
  29. package/bundles/codex/.codex/config.toml.example +36 -0
  30. package/bundles/codex/.codex/skills/coding/api-design/SKILL.md +249 -0
  31. package/bundles/codex/.codex/skills/coding/backend-development/SKILL.md +305 -0
  32. package/bundles/codex/.codex/skills/coding/code-review/SKILL.md +140 -0
  33. package/bundles/codex/.codex/skills/coding/codebase-audit/SKILL.md +204 -0
  34. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/SKILL.md +132 -0
  35. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/scripts/perf_sweep.py +249 -0
  36. package/bundles/codex/.codex/skills/coding/error-handling/SKILL.md +260 -0
  37. package/bundles/codex/.codex/skills/coding/fastapi-dev/SKILL.md +300 -0
  38. package/bundles/codex/.codex/skills/coding/javascript-typescript/SKILL.md +142 -0
  39. package/bundles/codex/.codex/skills/coding/python/SKILL.md +388 -0
  40. package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +486 -0
  41. package/bundles/codex/.codex/skills/coding/security-review/SKILL.md +205 -0
  42. package/bundles/codex/.codex/skills/coding/sql/SKILL.md +321 -0
  43. package/bundles/codex/.codex/skills/data/database-design/SKILL.md +177 -0
  44. package/bundles/codex/.codex/skills/data/db-diagram/SKILL.md +148 -0
  45. package/bundles/codex/.codex/skills/data/db-diagram/scripts/sql_to_graph.py +1212 -0
  46. package/bundles/codex/.codex/skills/devops/ci-cd-pipeline/SKILL.md +315 -0
  47. package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +195 -0
  48. package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +285 -0
  49. package/bundles/codex/.codex/skills/devops/safe-cleanup/SKILL.md +186 -0
  50. package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +217 -0
  51. package/bundles/codex/.codex/skills/devops/windows-deployment/SKILL.md +880 -0
  52. package/bundles/codex/.codex/skills/docs/code-documentation/SKILL.md +271 -0
  53. package/bundles/codex/.codex/skills/docs/explainer-doc/SKILL.md +97 -0
  54. package/bundles/codex/.codex/skills/docs/technical-writing/SKILL.md +286 -0
  55. package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +387 -0
  56. package/bundles/codex/.codex/skills/frontend/css-architecture/SKILL.md +305 -0
  57. package/bundles/codex/.codex/skills/frontend/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
  58. package/bundles/codex/.codex/skills/frontend/frontend-design/SKILL.md +193 -0
  59. package/bundles/codex/.codex/skills/frontend/frontend-design/references/my-tech-stack.md +127 -0
  60. package/bundles/codex/.codex/skills/frontend/mockup/SKILL.md +242 -0
  61. package/bundles/codex/.codex/skills/frontend/react-best-practices/SKILL.md +269 -0
  62. package/bundles/codex/.codex/skills/frontend/react-dev/README.md +404 -0
  63. package/bundles/codex/.codex/skills/frontend/react-dev/SKILL.md +459 -0
  64. package/bundles/codex/.codex/skills/frontend/react-dev/examples/generic-components.md +579 -0
  65. package/bundles/codex/.codex/skills/frontend/react-dev/examples/server-components.md +579 -0
  66. package/bundles/codex/.codex/skills/frontend/react-dev/references/event-handlers.md +574 -0
  67. package/bundles/codex/.codex/skills/frontend/react-dev/references/hooks.md +456 -0
  68. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-19-patterns.md +638 -0
  69. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-router.md +1002 -0
  70. package/bundles/codex/.codex/skills/frontend/react-dev/references/tanstack-router.md +587 -0
  71. package/bundles/codex/.codex/skills/frontend/ui-review/SKILL.md +176 -0
  72. package/bundles/codex/.codex/skills/frontend/ui-review/references/framework-fixes.md +471 -0
  73. package/bundles/codex/.codex/skills/frontend/ui-review/references/visual-checklist.md +236 -0
  74. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
  75. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
  76. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/SKILL.md +732 -0
  77. package/bundles/codex/.codex/skills/media/draw-io/SKILL.md +162 -0
  78. package/bundles/codex/.codex/skills/media/draw-io/references/aws-icons.md +677 -0
  79. package/bundles/codex/.codex/skills/media/draw-io/references/layout-guidelines.md +142 -0
  80. package/bundles/codex/.codex/skills/media/draw-io/references/troubleshooting.md +118 -0
  81. package/bundles/codex/.codex/skills/media/draw-io/references/workflows.md +103 -0
  82. package/bundles/codex/.codex/skills/media/draw-io/scripts/convert-drawio-to-png.sh +25 -0
  83. package/bundles/codex/.codex/skills/media/draw-io/scripts/find_aws_icon.py +79 -0
  84. package/bundles/codex/.codex/skills/media/mermaid-diagrams/SKILL.md +292 -0
  85. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
  86. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
  87. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/advanced-features.md +556 -0
  88. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  89. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/c4-diagrams.md +410 -0
  90. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/class-diagrams.md +361 -0
  91. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/erd-diagrams.md +510 -0
  92. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/flowcharts.md +450 -0
  93. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  94. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/troubleshooting.md +335 -0
  95. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/workflows.md +418 -0
  96. package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +243 -0
  97. package/bundles/codex/.codex/skills/media/particle-art/references/canvas-utils.ts +171 -0
  98. package/bundles/codex/.codex/skills/media/particle-art/references/dot-field.template.tsx +203 -0
  99. package/bundles/codex/.codex/skills/media/particle-art/references/flow-field.template.tsx +263 -0
  100. package/bundles/codex/.codex/skills/media/particle-art/references/node-shape.template.tsx +261 -0
  101. package/bundles/codex/.codex/skills/media/particle-art/references/shape-sampler.ts +281 -0
  102. package/bundles/codex/.codex/skills/media/particle-art/references/stipple-morph.template.tsx +167 -0
  103. package/bundles/codex/.codex/skills/media/particle-art/references/stipple.template.tsx +175 -0
  104. package/bundles/codex/.codex/skills/media/particle-art/references/trail-ghost.template.tsx +266 -0
  105. package/bundles/codex/.codex/skills/media/particle-art/references/usage-examples.md +320 -0
  106. package/bundles/codex/.codex/skills/testing/playwright/API_REFERENCE.md +653 -0
  107. package/bundles/codex/.codex/skills/testing/playwright/SKILL.md +454 -0
  108. package/bundles/codex/.codex/skills/testing/playwright/lib/helpers.js +441 -0
  109. package/bundles/codex/.codex/skills/testing/playwright/package.json +26 -0
  110. package/bundles/codex/.codex/skills/testing/playwright/run.js +228 -0
  111. package/bundles/codex/.codex/skills/testing/tdd-workflow/SKILL.md +188 -0
  112. package/bundles/codex/.codex/skills/testing/test-strategy/SKILL.md +155 -0
  113. package/bundles/codex/.codex/skills/testing/webapp-testing/LICENSE.txt +202 -0
  114. package/bundles/codex/.codex/skills/testing/webapp-testing/SKILL.md +97 -0
  115. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/console_logging.py +35 -0
  116. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/element_discovery.py +40 -0
  117. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/static_html_automation.py +33 -0
  118. package/bundles/codex/.codex/skills/testing/webapp-testing/scripts/with_server.py +106 -0
  119. package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +227 -0
  120. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +214 -0
  121. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +233 -0
  122. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +94 -0
  123. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +118 -0
  124. package/bundles/codex/.codex/skills/workflow/best-practices/SKILL.md +500 -0
  125. package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +263 -0
  126. package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +326 -0
  127. package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +245 -0
  128. package/bundles/codex/.codex/skills/workflow/best-practices/references/anti-patterns.md +571 -0
  129. package/bundles/codex/.codex/skills/workflow/best-practices/references/before-after-examples.md +1114 -0
  130. package/bundles/codex/.codex/skills/workflow/best-practices/references/best-practices-guide.md +513 -0
  131. package/bundles/codex/.codex/skills/workflow/best-practices/references/common-workflows.md +692 -0
  132. package/bundles/codex/.codex/skills/workflow/best-practices/references/prompt-patterns.md +547 -0
  133. package/bundles/codex/.codex/skills/workflow/brainstorming/SKILL.md +57 -0
  134. package/bundles/codex/.codex/skills/workflow/context-curator/SKILL.md +157 -0
  135. package/bundles/codex/.codex/skills/workflow/golden-plan/SKILL.md +586 -0
  136. package/bundles/codex/.codex/skills/workflow/preflight/SKILL.md +440 -0
  137. package/bundles/codex/.codex/skills/workflow/skill-creator/LICENSE.txt +202 -0
  138. package/bundles/codex/.codex/skills/workflow/skill-creator/SKILL.md +491 -0
  139. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/analyzer.md +274 -0
  140. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/comparator.md +202 -0
  141. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/grader.md +223 -0
  142. package/bundles/codex/.codex/skills/workflow/skill-creator/assets/eval_review.html +146 -0
  143. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/generate_review.py +471 -0
  144. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/viewer.html +1325 -0
  145. package/bundles/codex/.codex/skills/workflow/skill-creator/references/schemas.md +430 -0
  146. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/__init__.py +0 -0
  147. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/aggregate_benchmark.py +401 -0
  148. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/generate_report.py +326 -0
  149. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/improve_description.py +247 -0
  150. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/package_skill.py +136 -0
  151. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/quick_validate.py +103 -0
  152. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_eval.py +310 -0
  153. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_loop.py +328 -0
  154. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/utils.py +47 -0
  155. package/bundles/codex/AGENTS.md +146 -0
  156. package/bundles/manifest.json +4 -3
  157. package/dist/claude-deepseek.js +2 -2
  158. package/dist/claude-glm.js +2 -2
  159. package/dist/claude-oss.js +2 -2
  160. package/dist/cli.js +187 -56
  161. package/package.json +1 -1
  162. package/bundles/antigravity-plugin/scripts/dream_capture.py +0 -249
  163. package/bundles/antigravity-plugin/scripts/dream_memory.py +0 -438
  164. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  165. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  166. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  167. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  168. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  169. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  170. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  171. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  172. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  173. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  174. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  175. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  176. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  177. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  178. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  179. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  180. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  181. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  182. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  183. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  184. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  185. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  186. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  187. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  188. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  189. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  190. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  191. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  192. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  193. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  194. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  195. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  196. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  197. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  198. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  199. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  200. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  201. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  202. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  203. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  204. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  205. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  206. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  207. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  208. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  209. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  210. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  211. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  212. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  213. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  214. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  215. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  216. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  217. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  218. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  219. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  220. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  221. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  222. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  223. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  224. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  225. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  226. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  227. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  228. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  229. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  230. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  231. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  232. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  233. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  234. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  235. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  236. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  237. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  238. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  239. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  240. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  241. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  242. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  243. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  244. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: dashboard-perf-sweep
3
+ context: fork
4
+ description: Re-measure an app's dashboard/API endpoints for load-time regressions and decide, with a documented checklist (not a black-box verdict), whether a slow one is a candidate for the rs-kit summary-table refresher pattern — or needs an index, keyset paging, gzip, or nothing at all. Use when the user says "sweep dashboard performance", "check if this app needs rs-kit", "re-measure the perf tracker", "is this endpoint a refresher candidate", or when a dashboard-performance-tracker.md is stale and needs re-validating. Read-only by default (dev servers only; prod requires an explicit opt-in and human confirmation) and human-invoked, never scheduled -- it surfaces candidates, it does not enroll them.
5
+ ---
6
+
7
+ # dashboard-perf-sweep — re-measure, then judge the shape, not just the time
8
+
9
+ Today an app "earns" the rs-kit refresher pattern only when someone happens to be doing unrelated
10
+ work on it, hits a slow page, and measures it properly. That worked for a couple of apps in the
11
+ fleet, but a snapshot measurement goes stale — a page added last month, or a table that crossed a
12
+ growth threshold since, has no mechanism to surface itself. This skill re-measures on demand.
13
+
14
+ **What already exists and must NOT be rebuilt:** every app in the fleet has its own
15
+ `.caddis/kb/dashboard-performance-tracker.md` with real baseline measurements. The gap this closes
16
+ is **re-measurement and re-judgment**, not first-time discovery.
17
+
18
+ ## Explicit scope guardrails — do not relax without a new conversation
19
+
20
+ - **Read-only except the final tracker update.** No code changes, no schema changes, ever. The only
21
+ write this skill makes is a diffable update to the target app's own `dashboard-performance-tracker.md`.
22
+ - **Dev by default.** Measuring against prod requires an explicit opt-in flag from the user AND, per
23
+ this project's convention for risky/hard-to-reverse actions, confirmation before hitting a live
24
+ service.
25
+ - **Human-invoked, not scheduled.** Run this when a person chooses to — never wire it into a cron job
26
+ or background automation. It surfaces candidates; it does not enroll them.
27
+ - **rs-kit is one of several possible recommendations, never the only output.** The checklist below
28
+ must be able to conclude "needs an index," "needs keyset paging," "needs gzip/trimmed fields,"
29
+ "not currently a candidate" — recommending rs-kit only for the specific aggregation shape.
30
+
31
+ ## The decision model — two gates, not one number
32
+
33
+ **Gate 1 — time (mechanical).** `DASHBOARD-PERFORMANCE-STANDARD.md` Rule 6: the first, uncached load
34
+ of any dashboard endpoint must finish in **under ~1 second**. The harness script below applies this
35
+ gate automatically per endpoint. Passing gate 1 does **not** mean rs-kit — it just means "look closer."
36
+
37
+ **Gate 2 — shape (judgment, applied by you the agent, never automated).** rs-kit fixes exactly one
38
+ shape: a query that recomputes `O(all rows ever stored)` per request, against data that keeps
39
+ growing. Time alone is not sufficient evidence — the fleet's own history proves it:
40
+
41
+ | App | Cold time | Root cause | rs-kit? |
42
+ |---|---|---|---|
43
+ | App A | worst >60s, 5 real breaches | recurring full-table aggregation | **YES** |
44
+ | App B (pre-fix) | 14s–60s+ across several endpoints | recurring full-table aggregation | **YES** |
45
+ | App C | 10.3s | a single ~158MB LOB payload on 9.1k rows, not aggregation | **NO** — SQL aggregate + gzip |
46
+ | App D | 1.9s | cold JSON parse, no DB at all in prod | **NO** — warm the provider |
47
+ | App E | 202ms | n/a — never crossed gate 1 | **NO** |
48
+
49
+ A naive "slow ⇒ recommend rs-kit" tool would have wrongly flagged App C and App D. That already
50
+ happened once before the shape distinction was made explicit — don't repeat it.
51
+
52
+ ## Step 1 — build the endpoint list for this app
53
+
54
+ The tracker files are semi-structured (page names + backtick route fragments in a markdown table),
55
+ not a clean machine-parseable list — extract the list yourself, per app, each run:
56
+
57
+ 1. Read the target app's `.caddis/kb/dashboard-performance-tracker.md` — pull every "Page / endpoint"
58
+ entry, in particular anything marked ⏳ pending or not re-measured recently.
59
+ 2. If the app has a `UI_PAGE_GUIDE.md` (check root and `docs/reference/`), cross-check it for pages
60
+ **not yet in the tracker** — this is what catches drift, not just re-running the same old list. Not
61
+ every app has one; if it's missing, say so explicitly rather than silently only using the tracker.
62
+ 3. Write the result as a JSON file matching the harness's input shape:
63
+ ```json
64
+ [
65
+ {"name": "Historical Trends chart", "method": "GET", "path": "/api/trends/daily"},
66
+ {"name": "IW grid", "method": "POST", "path": "/raworkbench/investigation/query", "json": {}}
67
+ ]
68
+ ```
69
+ 4. Confirm with the user (or the app's own `run`/`webapp-testing` conventions) how to reach the dev
70
+ instance safely, and what auth the endpoints need (open / token / session cookie) — pass it via
71
+ `--header`.
72
+
73
+ ## Step 2 — start the dev server, then run the harness
74
+
75
+ Use the app's own `run` skill/convention to start it — this skill does not start dev servers itself,
76
+ only measures an already-reachable URL.
77
+
78
+ **Use `127.0.0.1`, never the hostname `localhost`, in `--base-url`.** On Windows, Python's `urllib`
79
+ resolves `localhost` dual-stack (tries IPv6 `::1` first) and can add a **spurious, rock-steady
80
+ ~1000ms** to every single request — cold *and* warm, on every endpoint including the framework's own
81
+ static docs page. It looks exactly like a real, uniform perf problem (equal cold/warm, present on
82
+ trivial routes too) and is not one. This cost real time during this skill's own validation (§
83
+ Validating below) before `127.0.0.1` was substituted and the true numbers — sub-15ms — appeared. If a
84
+ sweep ever comes back with a suspiciously uniform floor across unrelated endpoints, first time a
85
+ `/docs` or `/openapi.json` route on the same base URL before trusting the data.
86
+
87
+ ```bash
88
+ python <skill-dir>/scripts/perf_sweep.py --base-url http://127.0.0.1:<port> --endpoints endpoints.json
89
+ python <skill-dir>/scripts/perf_sweep.py --base-url http://127.0.0.1:<port> --endpoints endpoints.json \
90
+ --header "Cookie: session=..." --output report.json
91
+ ```
92
+
93
+ Cold = first request after the dev server's fresh start (or right after a cache-bust if it can't be
94
+ restarted cheaply); warm = the immediate second request. The report flags gate-1 breaches and prints
95
+ the cold/warm ratio — a big ratio with no cache in between already points at a query-shape problem,
96
+ not a cache-TTL one. **A page that errors or times out is a finding, not a script failure** — it's
97
+ printed as `[ERROR]`, never silently dropped.
98
+
99
+ ## Step 3 — apply the gate-2 checklist to every gate-1 breach
100
+
101
+ Force these questions, in order, for each slow endpoint — don't skip to a verdict:
102
+
103
+ 1. **Does response size explain most of the time** (large payload, not a slow query)? → not rs-kit;
104
+ recommend trimming fields / gzip / virtualization.
105
+ 2. **Is the slow part parsing/serialization, not the DB round-trip?** → not rs-kit; recommend
106
+ caching/warming the parsed form (App D precedent).
107
+ 3. **Does the query scale with total stored rows rather than the response size** — read the actual
108
+ SQL/query plan, not just the timing — **and is the same aggregation recomputed per request on data
109
+ that keeps growing?** → candidate for rs-kit.
110
+ 4. **Is it slow only at deep pagination (OFFSET)?** → not rs-kit; recommend keyset paging
111
+ (`exception_id`-style cursor, App B precedent).
112
+ 5. **Is a specific WHERE clause unseekable** (function-wrapped column, NVARCHAR/VARCHAR param
113
+ mismatch)? → not rs-kit; recommend an index or a param-type fix.
114
+
115
+ Link findings to real fleet precedent (the table above, the `nvarchar-param-varchar-column-scan`
116
+ pattern, the keyset-paging work) rather than describing fixes in the abstract — every category here
117
+ has already been solved once in this fleet.
118
+
119
+ ## Step 4 — update the tracker, diffably
120
+
121
+ Update the target app's own `dashboard-performance-tracker.md` in place with the new measurements and
122
+ verdicts, so drift becomes visible over time in the diff. Never silently overwrite it without the user
123
+ being able to see a before/after. Print a summary alongside the file edit.
124
+
125
+ ## Validating this skill against known ground truth
126
+
127
+ Before trusting a new app's output, or after changing the checklist, run the sweep against two
128
+ already-known apps in your fleet and confirm it reproduces the **already-established, human-verified**
129
+ conclusion for each: one that's genuinely fast (should conclude "not a candidate") and one with a
130
+ known aggregation breach (should conclude "aggregation-shaped, rs-kit candidate" for the pages
131
+ already identified). If the output disagrees with the known-good conclusion for either, that's a
132
+ checklist bug — fix the checklist, don't rationalize the disagreement away.
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env python3
2
+ """Cold/warm HTTP timing harness for the dashboard-perf-sweep skill.
3
+
4
+ Given a base URL and a list of endpoints, measures a COLD request (first hit) and a WARM
5
+ request (immediately after) per endpoint, safely: a timeout or connection error on one endpoint
6
+ is recorded as a finding, never a crash of the whole sweep (DASHBOARD-PERFORMANCE-STANDARD.md
7
+ Rule 6 gate-1 mechanics; the huge cold/warm gap without a cache in between is itself diagnostic
8
+ of a query-shape problem, not a cache-TTL one).
9
+
10
+ This harness does NOT start dev servers or know anything about a specific app -- that's the
11
+ `run` skill's job. It only measures a URL that is already reachable. stdlib-only (urllib), no
12
+ install, matching the other caddis tool scripts (oss_review.py etc.).
13
+
14
+ CLI:
15
+ python perf_sweep.py --base-url http://localhost:8000 --endpoints endpoints.json
16
+ python perf_sweep.py --base-url http://localhost:8000 --endpoints endpoints.json --output report.json
17
+ python perf_sweep.py --base-url http://localhost:8000 --endpoints endpoints.json --gate1-seconds 1.0
18
+
19
+ endpoints.json shape (a JSON list):
20
+ [
21
+ {"name": "Historical Trends chart", "method": "GET", "path": "/api/trends/daily"},
22
+ {"name": "IW grid", "method": "POST", "path": "/raworkbench/investigation/query",
23
+ "json": {"filters": {}}, "headers": {"Authorization": "Bearer ..."}}
24
+ ]
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import sys
31
+ import time
32
+ import urllib.error
33
+ import urllib.request
34
+ from dataclasses import asdict, dataclass, field
35
+ from typing import Any
36
+
37
+ DEFAULT_TIMEOUT_SECONDS = 30.0
38
+ DEFAULT_GATE1_SECONDS = 1.0 # DASHBOARD-PERFORMANCE-STANDARD.md Rule 6
39
+
40
+
41
+ @dataclass
42
+ class RequestResult:
43
+ ok: bool
44
+ status: int | None = None
45
+ elapsed_ms: float | None = None
46
+ error: str | None = None
47
+
48
+
49
+ @dataclass
50
+ class EndpointResult:
51
+ name: str
52
+ method: str
53
+ path: str
54
+ cold: RequestResult
55
+ warm: RequestResult | None = None
56
+ gate1_breach: bool = False
57
+
58
+
59
+ @dataclass
60
+ class SweepReport:
61
+ base_url: str
62
+ gate1_seconds: float
63
+ endpoints: list[EndpointResult] = field(default_factory=list)
64
+
65
+ def to_dict(self) -> dict[str, Any]:
66
+ return {
67
+ "base_url": self.base_url,
68
+ "gate1_seconds": self.gate1_seconds,
69
+ "endpoints": [
70
+ {
71
+ "name": e.name,
72
+ "method": e.method,
73
+ "path": e.path,
74
+ "cold": asdict(e.cold),
75
+ "warm": asdict(e.warm) if e.warm else None,
76
+ "gate1_breach": e.gate1_breach,
77
+ }
78
+ for e in self.endpoints
79
+ ],
80
+ }
81
+
82
+
83
+ def _do_request(
84
+ url: str,
85
+ method: str,
86
+ *,
87
+ json_body: dict[str, Any] | None = None,
88
+ headers: dict[str, str] | None = None,
89
+ timeout: float = DEFAULT_TIMEOUT_SECONDS,
90
+ ) -> RequestResult:
91
+ """One timed HTTP request. Never raises -- a timeout/connection/HTTP error becomes a
92
+ RequestResult with ok=False and a human-readable error, which is itself a sweep finding."""
93
+ data = None
94
+ req_headers = dict(headers or {})
95
+ if json_body is not None:
96
+ data = json.dumps(json_body).encode("utf-8")
97
+ req_headers.setdefault("Content-Type", "application/json")
98
+
99
+ req = urllib.request.Request(url, data=data, headers=req_headers, method=method)
100
+ start = time.perf_counter()
101
+ try:
102
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
103
+ resp.read()
104
+ elapsed_ms = (time.perf_counter() - start) * 1000.0
105
+ return RequestResult(ok=True, status=resp.status, elapsed_ms=elapsed_ms)
106
+ except urllib.error.HTTPError as exc:
107
+ # An HTTP error status still completed a round trip -- timing is a real finding.
108
+ elapsed_ms = (time.perf_counter() - start) * 1000.0
109
+ return RequestResult(ok=False, status=exc.code, elapsed_ms=elapsed_ms, error=f"HTTP {exc.code}")
110
+ except urllib.error.URLError as exc:
111
+ elapsed_ms = (time.perf_counter() - start) * 1000.0
112
+ return RequestResult(ok=False, elapsed_ms=elapsed_ms, error=f"connection error: {exc.reason}")
113
+ except TimeoutError:
114
+ elapsed_ms = (time.perf_counter() - start) * 1000.0
115
+ return RequestResult(ok=False, elapsed_ms=elapsed_ms, error=f"timeout after {timeout}s")
116
+
117
+
118
+ def sweep_endpoint(
119
+ base_url: str,
120
+ endpoint: dict[str, Any],
121
+ *,
122
+ timeout: float = DEFAULT_TIMEOUT_SECONDS,
123
+ gate1_seconds: float = DEFAULT_GATE1_SECONDS,
124
+ warm: bool = True,
125
+ extra_headers: dict[str, str] | None = None,
126
+ ) -> EndpointResult:
127
+ method = endpoint.get("method", "GET").upper()
128
+ path = endpoint["path"]
129
+ url = base_url.rstrip("/") + path
130
+ headers = dict(extra_headers or {})
131
+ headers.update(endpoint.get("headers", {}))
132
+ json_body = endpoint.get("json")
133
+
134
+ cold = _do_request(url, method, json_body=json_body, headers=headers, timeout=timeout)
135
+ warm_result = None
136
+ if warm:
137
+ warm_result = _do_request(url, method, json_body=json_body, headers=headers, timeout=timeout)
138
+
139
+ gate1_breach = bool(cold.ok and cold.elapsed_ms is not None and cold.elapsed_ms / 1000.0 > gate1_seconds)
140
+ return EndpointResult(
141
+ name=endpoint.get("name", path),
142
+ method=method,
143
+ path=path,
144
+ cold=cold,
145
+ warm=warm_result,
146
+ gate1_breach=gate1_breach,
147
+ )
148
+
149
+
150
+ def sweep(
151
+ base_url: str,
152
+ endpoints: list[dict[str, Any]],
153
+ *,
154
+ timeout: float = DEFAULT_TIMEOUT_SECONDS,
155
+ gate1_seconds: float = DEFAULT_GATE1_SECONDS,
156
+ warm: bool = True,
157
+ extra_headers: dict[str, str] | None = None,
158
+ ) -> SweepReport:
159
+ report = SweepReport(base_url=base_url, gate1_seconds=gate1_seconds)
160
+ for endpoint in endpoints:
161
+ report.endpoints.append(
162
+ sweep_endpoint(
163
+ base_url,
164
+ endpoint,
165
+ timeout=timeout,
166
+ gate1_seconds=gate1_seconds,
167
+ warm=warm,
168
+ extra_headers=extra_headers,
169
+ )
170
+ )
171
+ return report
172
+
173
+
174
+ def format_report(report: SweepReport) -> str:
175
+ lines = [f"Sweep: {report.base_url} (gate 1 = {report.gate1_seconds}s cold, uncached)", ""]
176
+ for e in report.endpoints:
177
+ if not e.cold.ok:
178
+ lines.append(f" [ERROR] {e.method:5s} {e.path:45s} {e.cold.error}")
179
+ continue
180
+ flag = "SLOW " if e.gate1_breach else " "
181
+ cold_s = f"{e.cold.elapsed_ms:8.1f}ms"
182
+ warm_s = f"{e.warm.elapsed_ms:8.1f}ms" if e.warm and e.warm.ok else "n/a"
183
+ gap = ""
184
+ if e.warm and e.warm.ok and e.cold.elapsed_ms and e.warm.elapsed_ms:
185
+ ratio = e.cold.elapsed_ms / max(e.warm.elapsed_ms, 0.01)
186
+ if ratio > 3:
187
+ gap = f" (cold/warm {ratio:.1f}x -- likely query-shape, not cache-TTL)"
188
+ lines.append(f" {flag}{e.method:5s} {e.path:45s} cold={cold_s} warm={warm_s}{gap}")
189
+ breaches = [e for e in report.endpoints if e.gate1_breach]
190
+ errors = [e for e in report.endpoints if not e.cold.ok]
191
+ problems = breaches + errors
192
+ lines.append("")
193
+ lines.append(
194
+ f"{len(problems)}/{len(report.endpoints)} endpoint(s) have a problem "
195
+ f"({len(breaches)} slow, {len(errors)} errored/timed out -- a timeout is a WORSE "
196
+ f"signal than a gate-1 breach, not a lesser one)."
197
+ )
198
+ if problems:
199
+ lines.append("Not itself a rs-kit verdict -- apply the shape checklist (SKILL.md) next.")
200
+ return "\n".join(lines)
201
+
202
+
203
+ def _parse_header(value: str) -> tuple[str, str]:
204
+ if ":" not in value:
205
+ raise argparse.ArgumentTypeError(f"--header must be 'Key: Value', got {value!r}")
206
+ key, _, val = value.partition(":")
207
+ return key.strip(), val.strip()
208
+
209
+
210
+ def main(argv: list[str] | None = None) -> int:
211
+ parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
212
+ parser.add_argument("--base-url", required=True, help="e.g. http://localhost:8703")
213
+ parser.add_argument("--endpoints", required=True, help="path to a JSON file (see module docstring)")
214
+ parser.add_argument("--timeout", type=float, default=DEFAULT_TIMEOUT_SECONDS)
215
+ parser.add_argument("--gate1-seconds", type=float, default=DEFAULT_GATE1_SECONDS)
216
+ parser.add_argument("--no-warm", action="store_true", help="skip the warm (second) request")
217
+ parser.add_argument("--header", action="append", default=[], type=_parse_header,
218
+ help="extra header applied to every request, repeatable: --header 'Cookie: session=...'")
219
+ parser.add_argument("--output", help="also write the JSON report to this path")
220
+ args = parser.parse_args(argv)
221
+
222
+ with open(args.endpoints, encoding="utf-8") as f:
223
+ endpoints = json.load(f)
224
+ if not isinstance(endpoints, list):
225
+ print(f"[FAIL] {args.endpoints} must contain a JSON list of endpoint objects", file=sys.stderr)
226
+ return 2
227
+
228
+ report = sweep(
229
+ args.base_url,
230
+ endpoints,
231
+ timeout=args.timeout,
232
+ gate1_seconds=args.gate1_seconds,
233
+ warm=not args.no_warm,
234
+ extra_headers=dict(args.header),
235
+ )
236
+
237
+ print(format_report(report))
238
+ if args.output:
239
+ with open(args.output, "w", encoding="utf-8") as f:
240
+ json.dump(report.to_dict(), f, indent=2)
241
+ print(f"\nWrote {args.output}")
242
+
243
+ breaches = [e for e in report.endpoints if e.gate1_breach]
244
+ errors = [e for e in report.endpoints if not e.cold.ok]
245
+ return 1 if (breaches or errors) else 0
246
+
247
+
248
+ if __name__ == "__main__":
249
+ raise SystemExit(main())
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: error-handling
3
+ description: Error handling patterns for Python and TypeScript applications. Use when designing error hierarchies, implementing retry logic, building error boundaries, or establishing logging strategies. Covers custom exceptions, result types, circuit breakers, and user-facing error messages.
4
+ ---
5
+
6
+ # Error Handling Skill
7
+
8
+ Errors are not exceptional — they are part of the contract. This skill defines how to classify, propagate, and recover from errors consistently.
9
+
10
+ ## 1. When to Apply This Skill
11
+
12
+ **Trigger conditions:**
13
+ - Designing error handling for a new service or feature
14
+ - "How should we handle errors in this module?"
15
+ - Building retry logic or circuit breakers
16
+ - Reviewing code with bare `except:` or swallowed errors
17
+ - Establishing error handling conventions for a project
18
+
19
+ ## 2. Error Classification
20
+
21
+ Every error falls into one of three categories. Handle each differently.
22
+
23
+ | Category | Retryable? | User Action? | Example |
24
+ |----------|-----------|-------------|---------|
25
+ | **Transient** | Yes | None (auto-retry) | Network timeout, DB connection dropped, rate limit |
26
+ | **Operational** | No | Inform user | Invalid input, resource not found, insufficient permissions |
27
+ | **Fatal** | No | Alert team | Corrupted state, config missing, unrecoverable assertion |
28
+
29
+ ## 3. Python Exception Hierarchy
30
+
31
+ Build domain-specific exceptions. Never raise raw `Exception`.
32
+
33
+ ```python
34
+ class AppError(Exception):
35
+ """Base error for the application."""
36
+ def __init__(self, message: str, code: str | None = None):
37
+ self.message = message
38
+ self.code = code or self.__class__.__name__
39
+ super().__init__(self.message)
40
+
41
+ # Operational errors (expected, handled gracefully)
42
+ class NotFoundError(AppError):
43
+ """Resource does not exist."""
44
+
45
+ class ValidationError(AppError):
46
+ """Input validation failed."""
47
+
48
+ class AuthorizationError(AppError):
49
+ """User not authorized for this action."""
50
+
51
+ # Transient errors (retry-eligible)
52
+ class TransientError(AppError):
53
+ """Temporary failure — safe to retry."""
54
+
55
+ class ExternalServiceError(TransientError):
56
+ """External API call failed."""
57
+
58
+ class DatabaseConnectionError(TransientError):
59
+ """Database connection lost."""
60
+ ```
61
+
62
+ ### Usage Patterns
63
+
64
+ ```python
65
+ # ✅ GOOD: Specific exception with context
66
+ def get_user(user_id: str) -> User:
67
+ user = repo.find_by_id(user_id)
68
+ if user is None:
69
+ raise NotFoundError(f"User {user_id} not found")
70
+ return user
71
+
72
+ # ✅ GOOD: Catch specific, re-raise as domain error
73
+ def fetch_external_data(url: str) -> dict:
74
+ try:
75
+ response = httpx.get(url, timeout=10)
76
+ response.raise_for_status()
77
+ return response.json()
78
+ except httpx.TimeoutException as e:
79
+ raise ExternalServiceError(f"Timeout calling {url}") from e
80
+ except httpx.HTTPStatusError as e:
81
+ raise ExternalServiceError(f"HTTP {e.response.status_code} from {url}") from e
82
+
83
+ # ❌ BAD: Bare except swallows everything
84
+ try:
85
+ result = process()
86
+ except:
87
+ pass
88
+
89
+ # ❌ BAD: Catching too broadly
90
+ try:
91
+ result = process()
92
+ except Exception:
93
+ logger.error("Something went wrong")
94
+ return None # Hides the real error
95
+ ```
96
+
97
+ ## 4. TypeScript Error Patterns
98
+
99
+ ### Result Type (for expected failures)
100
+
101
+ ```typescript
102
+ type Result<T, E = Error> =
103
+ | { ok: true; value: T }
104
+ | { ok: false; error: E };
105
+
106
+ function parseConfig(raw: string): Result<Config, ValidationError> {
107
+ try {
108
+ const parsed = JSON.parse(raw);
109
+ if (!isValidConfig(parsed)) {
110
+ return { ok: false, error: new ValidationError("Invalid config shape") };
111
+ }
112
+ return { ok: true, value: parsed as Config };
113
+ } catch {
114
+ return { ok: false, error: new ValidationError("Invalid JSON") };
115
+ }
116
+ }
117
+
118
+ // Usage — caller must handle both cases
119
+ const result = parseConfig(rawInput);
120
+ if (!result.ok) {
121
+ showError(result.error.message);
122
+ return;
123
+ }
124
+ useConfig(result.value);
125
+ ```
126
+
127
+ ### Error Boundaries (React)
128
+
129
+ ```tsx
130
+ 'use client';
131
+ import { Component, type ReactNode } from 'react';
132
+
133
+ interface Props { children: ReactNode; fallback: ReactNode; }
134
+ interface State { hasError: boolean; }
135
+
136
+ export class ErrorBoundary extends Component<Props, State> {
137
+ state: State = { hasError: false };
138
+
139
+ static getDerivedStateFromError(): State {
140
+ return { hasError: true };
141
+ }
142
+
143
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
144
+ console.error('Component error:', error, info.componentStack);
145
+ // Report to error tracking service
146
+ }
147
+
148
+ render() {
149
+ return this.state.hasError ? this.props.fallback : this.props.children;
150
+ }
151
+ }
152
+ ```
153
+
154
+ ## 5. Retry with Exponential Backoff
155
+
156
+ ```python
157
+ import asyncio
158
+ import random
159
+ from loguru import logger
160
+
161
+ async def retry_with_backoff(
162
+ fn,
163
+ max_retries: int = 3,
164
+ base_delay: float = 1.0,
165
+ max_delay: float = 30.0,
166
+ retryable_exceptions: tuple = (TransientError,),
167
+ ):
168
+ """Retry a function with exponential backoff and jitter."""
169
+ for attempt in range(max_retries + 1):
170
+ try:
171
+ return await fn()
172
+ except retryable_exceptions as e:
173
+ if attempt == max_retries:
174
+ logger.error(f"All {max_retries} retries exhausted: {e}")
175
+ raise
176
+ delay = min(base_delay * (2 ** attempt), max_delay)
177
+ jitter = random.uniform(0, delay * 0.1)
178
+ logger.warning(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay:.1f}s")
179
+ await asyncio.sleep(delay + jitter)
180
+ ```
181
+
182
+ ## 6. FastAPI Error Handling
183
+
184
+ ```python
185
+ from fastapi import FastAPI, Request
186
+ from fastapi.responses import JSONResponse
187
+ from loguru import logger
188
+
189
+ app = FastAPI()
190
+
191
+ @app.exception_handler(NotFoundError)
192
+ async def not_found_handler(request: Request, exc: NotFoundError):
193
+ return JSONResponse(status_code=404, content={"error": exc.code, "message": exc.message})
194
+
195
+ @app.exception_handler(ValidationError)
196
+ async def validation_handler(request: Request, exc: ValidationError):
197
+ return JSONResponse(status_code=422, content={"error": exc.code, "message": exc.message})
198
+
199
+ @app.exception_handler(AuthorizationError)
200
+ async def auth_handler(request: Request, exc: AuthorizationError):
201
+ return JSONResponse(status_code=403, content={"error": exc.code, "message": exc.message})
202
+
203
+ @app.exception_handler(Exception)
204
+ async def unhandled_handler(request: Request, exc: Exception):
205
+ logger.exception(f"Unhandled error on {request.method} {request.url}")
206
+ # Never expose internal details to the client
207
+ return JSONResponse(status_code=500, content={"error": "InternalError", "message": "An internal error occurred."})
208
+ ```
209
+
210
+ ## 7. Logging Errors Correctly
211
+
212
+ ```python
213
+ from loguru import logger
214
+
215
+ # ✅ GOOD: Log with context, not just the message
216
+ logger.error(f"Failed to process order {order_id}: {e}", order_id=order_id, customer_id=customer_id)
217
+
218
+ # ✅ GOOD: Use exception() to capture stack trace
219
+ try:
220
+ process_order(order)
221
+ except Exception as e:
222
+ logger.exception(f"Order processing failed for {order.id}")
223
+ raise
224
+
225
+ # ❌ BAD: Logging sensitive data
226
+ logger.error(f"Auth failed for {username} with password {password}")
227
+
228
+ # ❌ BAD: Logging without context
229
+ logger.error("Something failed")
230
+ ```
231
+
232
+ ## 8. Error Message Guidelines
233
+
234
+ | Audience | Include | Exclude |
235
+ |----------|---------|---------|
236
+ | **End user** | What happened, what to do next | Stack traces, internal IDs, SQL errors |
237
+ | **Developer (logs)** | Full context, request ID, stack trace | User passwords, tokens, PII |
238
+ | **API consumer** | Error code, human message, field-level detail | Server internals, file paths |
239
+
240
+ ```python
241
+ # User-facing message
242
+ "Unable to load your dashboard. Please try again in a few minutes."
243
+
244
+ # API response
245
+ {"error": "ValidationError", "message": "Email format is invalid", "field": "email"}
246
+
247
+ # Log entry
248
+ "Validation failed on POST /api/users: email='not-an-email' — rejected by regex validator"
249
+ ```
250
+
251
+ ## 9. Anti-Patterns
252
+
253
+ | Anti-Pattern | Problem | Fix |
254
+ |---|---|---|
255
+ | Bare `except:` / `except Exception:` | Catches KeyboardInterrupt, SystemExit | Catch specific exceptions |
256
+ | `return None` on error | Caller has no idea what went wrong | Raise typed exception |
257
+ | Logging and re-raising | Double logging, noisy | Log at the boundary, not at every layer |
258
+ | String error codes | Typos, no autocomplete | Enum or class-based error codes |
259
+ | Swallowing errors in background tasks | Silent failures, data loss | Log + alert + dead-letter queue |
260
+ | Generic "Something went wrong" | User can't self-serve | Specific message + action hint |