stream_weaver 0.3.0

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 (381) hide show
  1. checksums.yaml +7 -0
  2. data/.beads/.gitignore +77 -0
  3. data/.beads/README.md +81 -0
  4. data/.beads/config.yaml +54 -0
  5. data/.beads/metadata.json +7 -0
  6. data/.rspec +3 -0
  7. data/AGENTS.md +91 -0
  8. data/CHANGELOG.md +294 -0
  9. data/CLAUDE.md +67 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +565 -0
  12. data/Rakefile +13 -0
  13. data/assets/streamweaver-hero.jpg +0 -0
  14. data/bench/baselines/ledger.rb +58 -0
  15. data/bench/baselines/warroom.rb +51 -0
  16. data/bench/fixtures/ledger.rb +76 -0
  17. data/bench/fixtures/warroom.rb +60 -0
  18. data/bench/results/6daf8b8.md +102 -0
  19. data/bench/results/c8d749b.md +102 -0
  20. data/bench/results/eb06ab9.md +102 -0
  21. data/bench/run.rb +151 -0
  22. data/bench/support.rb +84 -0
  23. data/copy_this/dto_run_sample_run_7631.html +220 -0
  24. data/docs/SERVICE_MODE.md +302 -0
  25. data/docs/architecture/how_streamweaver_works.md +772 -0
  26. data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
  27. data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
  28. data/docs/canvas-ipc-session-summary.md +127 -0
  29. data/docs/canvas-panel-workflow.md +172 -0
  30. data/docs/canvas-read.md +147 -0
  31. data/docs/canvas-roadmap.md +275 -0
  32. data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
  33. data/docs/claude-code-companion-skill-spec.md +567 -0
  34. data/docs/components_reference.md +1223 -0
  35. data/docs/crud-patterns.md +265 -0
  36. data/docs/endpoints.md +122 -0
  37. data/docs/for_llms.md +1 -0
  38. data/docs/form-patterns.md +165 -0
  39. data/docs/frontend-only.md +169 -0
  40. data/docs/html-artifact-audit.md +238 -0
  41. data/docs/ideas/2025-01-01-as-a-service.md +203 -0
  42. data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
  43. data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
  44. data/docs/ideas/dhh-review-future-refactors.md +142 -0
  45. data/docs/opal-jamstack.md +47 -0
  46. data/docs/opal-npm-direction.md +184 -0
  47. data/docs/opal-spike-findings.md +194 -0
  48. data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
  49. data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
  50. data/docs/plans/2026-01-02-charts-design.md +288 -0
  51. data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
  52. data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
  53. data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
  54. data/docs/plans/canvas-claude-project-design.md +238 -0
  55. data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
  56. data/docs/plans/org-doc-preview-surfaces.md +293 -0
  57. data/docs/plans/shadcn-polish-plan.md +417 -0
  58. data/docs/porting-artifacts.md +252 -0
  59. data/docs/reference/agent-skills-comparison.md +369 -0
  60. data/docs/reference/travel-state-prd.artifact.html +780 -0
  61. data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
  62. data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
  63. data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
  64. data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
  65. data/docs/research/frontend-only-matrix.md +278 -0
  66. data/docs/research/streamweaver-way-spike-findings.md +529 -0
  67. data/docs/resource-dsl.md +342 -0
  68. data/docs/routing.md +302 -0
  69. data/docs/ruby-ui-comparison.md +319 -0
  70. data/docs/shared-dsl-fragments.md +356 -0
  71. data/docs/streamweaver-for-ai-agents.md +401 -0
  72. data/docs/streamweaver-frontend-vision.md +123 -0
  73. data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
  74. data/docs/streamweaver_canvas/save_example.rb +9 -0
  75. data/docs/templates.md +213 -0
  76. data/docs/testing.md +155 -0
  77. data/docs/theming-hooks.md +281 -0
  78. data/docs/tutorials/the-streamweaver-way.md +882 -0
  79. data/docs/university/capability-inventory.md +137 -0
  80. data/docs/university/dependency-survey.md +114 -0
  81. data/docs/university/design-spec.md +217 -0
  82. data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
  83. data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
  84. data/docs/university/mockups/course-list-dark.png +0 -0
  85. data/docs/university/mockups/course-list-light.png +0 -0
  86. data/docs/university/mockups/course_canvas_mockup.rb +741 -0
  87. data/docs/university/mockups/step-screen-dark.png +0 -0
  88. data/docs/university/mockups/step-screen-light.png +0 -0
  89. data/docs/university/roadmap.md +72 -0
  90. data/docs/university/send-to-coworker.md +77 -0
  91. data/docs/university/worker-session-mining.md +109 -0
  92. data/docs/visual/browser-rendering-spike.md +173 -0
  93. data/docs/visual/builder-visual-plan-analysis.md +378 -0
  94. data/docs/visual/sw-plan-format-exploration.md +511 -0
  95. data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
  96. data/docs/visual-skills/PROGRESS.md +60 -0
  97. data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
  98. data/docs/visual-skills/analysis/components.md +317 -0
  99. data/docs/visual-skills/analysis/overlap.md +360 -0
  100. data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
  101. data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
  102. data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
  103. data/docs/visual-skills/analysis/visual-explainer.md +964 -0
  104. data/docs/visual-skills/blog/blog-series-outline.md +39 -0
  105. data/docs/visual-skills/blog/token-efficiency.md +73 -0
  106. data/docs/visual-skills/design/architecture.md +1725 -0
  107. data/docs/visual-skills/design/codex-review.md +340 -0
  108. data/docs/visual-skills/design/dhh-review.md +209 -0
  109. data/docs/visual-skills/design/evolution.md +100 -0
  110. data/docs/visual-skills/design/gemini-review.md +55 -0
  111. data/docs/visual-skills/design/review-synthesis.md +149 -0
  112. data/docs/visual-skills/implementation/STATE.md +22 -0
  113. data/docs/visual-skills/implementation/plan.md +347 -0
  114. data/docs/visual-skills/implementation/spike-findings.md +237 -0
  115. data/docs/visual-skills/implementation/tasks.md +702 -0
  116. data/docs/visual-skills/lessons-learned/process.md +145 -0
  117. data/examples/README.md +96 -0
  118. data/examples/advanced/all_components.rb +177 -0
  119. data/examples/advanced/examples_browser.rb +394 -0
  120. data/examples/advanced/teachables_browser.rb +261 -0
  121. data/examples/advanced/theme_tweaker.rb +366 -0
  122. data/examples/advanced/tutorial.rb +1528 -0
  123. data/examples/agentic/agentic_form.rb +30 -0
  124. data/examples/agentic/agentic_form_autoclose.rb +30 -0
  125. data/examples/agentic/cultivation_tracker.rb +69 -0
  126. data/examples/basic/hello_world.rb +22 -0
  127. data/examples/basic/opal_tabs_table.rb +44 -0
  128. data/examples/basic/todo_list.rb +39 -0
  129. data/examples/button_loading_test.rb +36 -0
  130. data/examples/canvas/mermaid_canvas_demo.sh +151 -0
  131. data/examples/charts/bar_chart_demo.rb +57 -0
  132. data/examples/charts/line_chart_demo.rb +73 -0
  133. data/examples/charts/pie_area_demo.rb +87 -0
  134. data/examples/charts/stacked_bar_chart_demo.rb +69 -0
  135. data/examples/claude_code/README.md +85 -0
  136. data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
  137. data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
  138. data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
  139. data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
  140. data/examples/claude_code/codebreaker/README.md +213 -0
  141. data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
  142. data/examples/claude_code/tutorial/README.md +102 -0
  143. data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
  144. data/examples/claude_code/verification_flow/README.md +126 -0
  145. data/examples/components/annotated_code_demo.rb +54 -0
  146. data/examples/components/callout_demo.rb +33 -0
  147. data/examples/components/checkbox_group_demo.rb +46 -0
  148. data/examples/components/design_review.css +468 -0
  149. data/examples/components/design_review_demo.rb +44 -0
  150. data/examples/components/design_review_dsl.rb +300 -0
  151. data/examples/components/diff_block_demo.rb +112 -0
  152. data/examples/components/events_demo.rb +184 -0
  153. data/examples/components/form_demo.rb +62 -0
  154. data/examples/components/lesson_demo.rb +53 -0
  155. data/examples/components/markdown_demo.rb +110 -0
  156. data/examples/components/mermaid_demo.rb +166 -0
  157. data/examples/components/pareto_set.rb +64 -0
  158. data/examples/components/prd_demo.rb +21 -0
  159. data/examples/components/prd_dsl.rb +385 -0
  160. data/examples/components/quiz_demo.rb +47 -0
  161. data/examples/components/run_viewer_demo.rb +100 -0
  162. data/examples/components/score_and_collapsible_demo.rb +82 -0
  163. data/examples/components/select_stale_value_smoke_test.rb +39 -0
  164. data/examples/components/table_demo.rb +247 -0
  165. data/examples/components/timer_with_state_demo.rb +58 -0
  166. data/examples/components/todo_due_dates.rb +63 -0
  167. data/examples/components/uat_gaps_demo.rb +112 -0
  168. data/examples/dashboard/feed_simulator.rb +60 -0
  169. data/examples/dashboard/live_dashboard.rb +80 -0
  170. data/examples/dashboard_components.rb +108 -0
  171. data/examples/deferred_fragments_demo.rb +62 -0
  172. data/examples/generate_more_spike/README.md +63 -0
  173. data/examples/generate_more_spike/app.rb +441 -0
  174. data/examples/git_health.sh +401 -0
  175. data/examples/layout/layout_components_demo.rb +174 -0
  176. data/examples/layout/modal_demo.rb +215 -0
  177. data/examples/layout/navigation_demo.rb +227 -0
  178. data/examples/layout/route_tabs_demo.rb +52 -0
  179. data/examples/layout/routing_demo.rb +52 -0
  180. data/examples/layout/scroll_box_demo.rb +154 -0
  181. data/examples/lazy_fragments_demo.rb +151 -0
  182. data/examples/my_todos/README.md +29 -0
  183. data/examples/my_todos/my_todos.rb +312 -0
  184. data/examples/my_todos/store.rb +86 -0
  185. data/examples/opal/reactive_demo.rb +62 -0
  186. data/examples/opal/scenarios/s1_counter.rb +15 -0
  187. data/examples/opal/scenarios/s2_search_filter.rb +17 -0
  188. data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
  189. data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
  190. data/examples/opal/scenarios/s5_watch.rb +39 -0
  191. data/examples/opal/scenarios/s6_on_start.rb +20 -0
  192. data/examples/opal/scenarios/s7_wizard.rb +33 -0
  193. data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
  194. data/examples/opal/scenarios/s9_dashboard.rb +27 -0
  195. data/examples/operations_dashboard_demo.rb +167 -0
  196. data/examples/panel_demo.sh +447 -0
  197. data/examples/parity/assets/tyrion_slice.css +86 -0
  198. data/examples/parity/rivet_people_slice.rb +182 -0
  199. data/examples/parity/tyrion_components.css +777 -0
  200. data/examples/parity/tyrion_warroom_components.rb +414 -0
  201. data/examples/parity/tyrion_warroom_slice.rb +549 -0
  202. data/examples/puma_dev/README.md +124 -0
  203. data/examples/puma_dev/config.ru +34 -0
  204. data/examples/puma_dev/standalone_app.rb +34 -0
  205. data/examples/scaffolding/blog.rb +49 -0
  206. data/examples/scaffolding/utf_lite.rb +105 -0
  207. data/examples/styling/feedback_demo.rb +229 -0
  208. data/examples/styling/style_showcase.rb +172 -0
  209. data/examples/styling/theme_demo.rb +508 -0
  210. data/examples/timer_health_checker.rb +111 -0
  211. data/examples/timer_showcase.rb +131 -0
  212. data/examples/tutorials/render_markdown.rb +112 -0
  213. data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
  214. data/examples/tutorials/tutorial_content.rb +1082 -0
  215. data/examples/visual_skills/design_deck_demo.rb +314 -0
  216. data/examples/visual_skills/explainer_demo.rb +499 -0
  217. data/exe/streamweaver +9 -0
  218. data/gsd/ROADMAP-1.0.md +167 -0
  219. data/gsd/STATE.md +13 -0
  220. data/gsd/research/market-positioning-research.md +139 -0
  221. data/gsd/research/production-patterns-research.md +270 -0
  222. data/gsd/research/repo-audit-1.0.md +274 -0
  223. data/lib/stream_weaver/action_token.rb +58 -0
  224. data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
  225. data/lib/stream_weaver/adapter/base.rb +591 -0
  226. data/lib/stream_weaver/adapter/opal.rb +334 -0
  227. data/lib/stream_weaver/adapter/static.rb +1118 -0
  228. data/lib/stream_weaver/admin.rb +176 -0
  229. data/lib/stream_weaver/app.rb +1821 -0
  230. data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
  231. data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
  232. data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
  233. data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
  234. data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
  235. data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
  236. data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
  237. data/lib/stream_weaver/canvas/bridge.rb +239 -0
  238. data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
  239. data/lib/stream_weaver/canvas/client.rb +298 -0
  240. data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
  241. data/lib/stream_weaver/canvas/doc_store.rb +252 -0
  242. data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
  243. data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
  244. data/lib/stream_weaver/canvas/gist_store.rb +135 -0
  245. data/lib/stream_weaver/canvas/helpers.rb +109 -0
  246. data/lib/stream_weaver/canvas/history.rb +90 -0
  247. data/lib/stream_weaver/canvas/protocol.rb +86 -0
  248. data/lib/stream_weaver/canvas/reader.rb +853 -0
  249. data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
  250. data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
  251. data/lib/stream_weaver/canvas/session.rb +132 -0
  252. data/lib/stream_weaver/cli.rb +3235 -0
  253. data/lib/stream_weaver/component_assets.rb +70 -0
  254. data/lib/stream_weaver/component_registry.rb +67 -0
  255. data/lib/stream_weaver/component_renderer.rb +48 -0
  256. data/lib/stream_weaver/components/annotated_code.rb +53 -0
  257. data/lib/stream_weaver/components/api_endpoint.rb +42 -0
  258. data/lib/stream_weaver/components/callout.rb +59 -0
  259. data/lib/stream_weaver/components/chart.rb +84 -0
  260. data/lib/stream_weaver/components/code_block.rb +77 -0
  261. data/lib/stream_weaver/components/comparison.rb +39 -0
  262. data/lib/stream_weaver/components/decision.rb +38 -0
  263. data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
  264. data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
  265. data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
  266. data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
  267. data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
  268. data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
  269. data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
  270. data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
  271. data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
  272. data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
  273. data/lib/stream_weaver/components/diff_block.rb +125 -0
  274. data/lib/stream_weaver/components/doc_header.rb +57 -0
  275. data/lib/stream_weaver/components/image_block.rb +70 -0
  276. data/lib/stream_weaver/components/implementation_map.rb +33 -0
  277. data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
  278. data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
  279. data/lib/stream_weaver/components/mermaid.rb +79 -0
  280. data/lib/stream_weaver/components/pipeline.rb +63 -0
  281. data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
  282. data/lib/stream_weaver/components/slide_container.rb +141 -0
  283. data/lib/stream_weaver/components/timeline_event.rb +58 -0
  284. data/lib/stream_weaver/components/wireframe.rb +29 -0
  285. data/lib/stream_weaver/components/wireframe_block.rb +34 -0
  286. data/lib/stream_weaver/components.rb +2711 -0
  287. data/lib/stream_weaver/css.rb +230 -0
  288. data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
  289. data/lib/stream_weaver/display_dsl.rb +1004 -0
  290. data/lib/stream_weaver/export/html_exporter.rb +478 -0
  291. data/lib/stream_weaver/feed.rb +34 -0
  292. data/lib/stream_weaver/feed_builder.rb +31 -0
  293. data/lib/stream_weaver/fonts.rb +33 -0
  294. data/lib/stream_weaver/interaction_runner.rb +487 -0
  295. data/lib/stream_weaver/iterm.rb +460 -0
  296. data/lib/stream_weaver/layout_registry.rb +92 -0
  297. data/lib/stream_weaver/opal/bridge.rb +52 -0
  298. data/lib/stream_weaver/opal/builder.rb +193 -0
  299. data/lib/stream_weaver/opal/env.rb +29 -0
  300. data/lib/stream_weaver/opal/reactive_state.rb +75 -0
  301. data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
  302. data/lib/stream_weaver/opal/renderer.rb +77 -0
  303. data/lib/stream_weaver/opal/runtime.rb +250 -0
  304. data/lib/stream_weaver/opal/shell.rb +145 -0
  305. data/lib/stream_weaver/opal/string_bridge.rb +50 -0
  306. data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
  307. data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
  308. data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
  309. data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
  310. data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
  311. data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
  312. data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
  313. data/lib/stream_weaver/opal_entry.rb +136 -0
  314. data/lib/stream_weaver/org/inline.rb +95 -0
  315. data/lib/stream_weaver/org/reader.rb +561 -0
  316. data/lib/stream_weaver/org/recording_context.rb +86 -0
  317. data/lib/stream_weaver/org/source_splitter.rb +63 -0
  318. data/lib/stream_weaver/org/writer.rb +300 -0
  319. data/lib/stream_weaver/page_shell.rb +530 -0
  320. data/lib/stream_weaver/portfile.rb +79 -0
  321. data/lib/stream_weaver/pushable.rb +42 -0
  322. data/lib/stream_weaver/resource/default_views.rb +111 -0
  323. data/lib/stream_weaver/resource/field_input.rb +25 -0
  324. data/lib/stream_weaver/resource/state_keys.rb +16 -0
  325. data/lib/stream_weaver/resource/store.rb +18 -0
  326. data/lib/stream_weaver/resource.rb +104 -0
  327. data/lib/stream_weaver/server.rb +1471 -0
  328. data/lib/stream_weaver/service.rb +1240 -0
  329. data/lib/stream_weaver/service_client.rb +104 -0
  330. data/lib/stream_weaver/session_store.rb +186 -0
  331. data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
  332. data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
  333. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
  334. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
  335. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
  336. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
  337. data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
  338. data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
  339. data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
  340. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
  341. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
  342. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
  343. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
  344. data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
  345. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
  346. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
  347. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
  348. data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
  349. data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
  350. data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
  351. data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
  352. data/lib/stream_weaver/streamer.rb +63 -0
  353. data/lib/stream_weaver/templates/choices.rb +149 -0
  354. data/lib/stream_weaver/templates/code.rb +157 -0
  355. data/lib/stream_weaver/templates/confirm.rb +110 -0
  356. data/lib/stream_weaver/templates/diff.rb +195 -0
  357. data/lib/stream_weaver/templates/info.rb +142 -0
  358. data/lib/stream_weaver/templates/table.rb +169 -0
  359. data/lib/stream_weaver/templates/wizard.rb +271 -0
  360. data/lib/stream_weaver/theme/auto_mode.rb +116 -0
  361. data/lib/stream_weaver/theme/presets.rb +555 -0
  362. data/lib/stream_weaver/theme.rb +639 -0
  363. data/lib/stream_weaver/university/canvas.rb +924 -0
  364. data/lib/stream_weaver/university/course.rb +699 -0
  365. data/lib/stream_weaver/university/demos/counter.rb +33 -0
  366. data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
  367. data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
  368. data/lib/stream_weaver/university/demos.rb +50 -0
  369. data/lib/stream_weaver/university/listener.rb +467 -0
  370. data/lib/stream_weaver/university/progress.rb +201 -0
  371. data/lib/stream_weaver/university/runner.rb +138 -0
  372. data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
  373. data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
  374. data/lib/stream_weaver/utils.rb +31 -0
  375. data/lib/stream_weaver/version.rb +5 -0
  376. data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
  377. data/lib/stream_weaver/views.rb +3940 -0
  378. data/lib/stream_weaver.rb +122 -0
  379. data/llms.txt +1269 -0
  380. data/sig/stream_weaver.rbs +4 -0
  381. metadata +598 -0
@@ -0,0 +1,340 @@
1
+ # Architecture Review: StreamWeaver Visual Skills
2
+
3
+ *Reviewer: Claude Opus (second-opinion review)*
4
+ *Date: 2026-03-12*
5
+ *Document under review: `architecture.md` (1618 lines)*
6
+
7
+ ---
8
+
9
+ ## Overall Assessment
10
+
11
+ This is a well-structured architecture document. The design philosophy is sound -- "The DSL IS the API" is the right bet, and the decision to follow existing StreamWeaver patterns rather than introduce parallel systems will pay dividends. The overlap analysis is thorough and the 37% shared figure is credible.
12
+
13
+ That said, there are several areas where I see risk, over-engineering, or missing considerations. This review is organized around the nine focus areas requested.
14
+
15
+ ---
16
+
17
+ ## 1. Agent Communication Protocol (Section 6)
18
+
19
+ ### The Good
20
+
21
+ "Agent writes Ruby script, runs it, reads stdout" is the correct primary protocol for the StreamWeaver ecosystem. It leverages the existing `run_once!` pattern and keeps the DSL as the single source of truth. For agents that already run in a Ruby-capable environment (Claude Code, Pi), this is zero friction.
22
+
23
+ ### The Concern: Agents That Cannot Run Ruby
24
+
25
+ The design acknowledges only one protocol. What about:
26
+ - **Web-based agents** that can make HTTP calls but cannot execute arbitrary Ruby
27
+ - **Codex** running in a sandboxed environment where `ruby` may not be available or the gem may not be installed
28
+ - **Multi-agent orchestration** where a coordinator dispatches to StreamWeaver without running Ruby locally
29
+
30
+ **Recommendation:** Add a thin JSON-over-HTTP API as a secondary protocol. Not as the primary path, but as a fallback. The `Skills` classes in Section 6.5 already accept structured data (`slides:` as an array of hashes). Expose that same interface as a POST endpoint:
31
+
32
+ ```
33
+ POST /api/deck { title: "...", slides: [...] }
34
+ POST /api/explainer { title: "...", sections: [...] }
35
+ ```
36
+
37
+ The server translates JSON to DSL calls internally. This is a small surface area (two endpoints) and dramatically widens the agent compatibility story. It can be Phase 5 work -- it does not block the core implementation -- but it should be in the design document as a planned extension rather than absent entirely.
38
+
39
+ ### The Concern: `run_once!` Lifecycle and Generate-More Tension
40
+
41
+ The `run_once!` pattern assumes a single request-response cycle: start, collect input, return result, shut down. But the generate-more loop requires the agent script to remain active and responsive *during* user interaction. The document shows this with a `Thread.new` polling loop, but the implications are under-explored:
42
+
43
+ - The agent script must now be a long-running process, not a fire-and-forget script
44
+ - If the agent's Ruby process crashes mid-session, the user is stuck with a dead Generate button
45
+ - The `run_once!` shutdown trigger (submit) must cleanly terminate the polling thread
46
+
47
+ This is workable but the document should explicitly address the lifecycle: how does the polling thread know to stop? What happens if the agent process is killed? The heartbeat/watchdog from pi-design-deck seems relevant here and is mentioned in the overlap analysis but absent from the architecture.
48
+
49
+ ---
50
+
51
+ ## 2. Generate-More Loop (Section 7)
52
+
53
+ ### Polling is the Right Call -- With Caveats
54
+
55
+ I agree with the recommendation of polling over callbacks or stdout. The reasoning is correct: simplicity wins when the operation being waited on (LLM generation) takes 5-15 seconds anyway. A 1-2 second poll interval is noise.
56
+
57
+ ### What is Missing
58
+
59
+ **Concurrency prevention is unaddressed.** The original pi-design-deck has explicit concurrent-generation prevention. What happens if the user clicks "Generate" twice quickly? The document shows `settings.generate_requests << request` using a simple append -- there is no deduplication or "already generating for this slide" guard. This needs to be in the state machine diagram.
60
+
61
+ **The state machine is too simple.** It covers the happy path and the timeout path. Missing states:
62
+ - **CANCELLED** -- user navigates away from the slide while generation is in progress
63
+ - **ERROR** -- the agent's LLM call fails (rate limit, network error, context too long)
64
+ - **PARTIAL** -- some options arrive but the agent fails mid-batch
65
+
66
+ The state machine should also address: what happens to pending skeletons when the user navigates to a different slide and back? Are they preserved? Cleared?
67
+
68
+ **WebSockets vs. SSE vs. polling:** The document does not mention WebSockets at all. For this specific use case, SSE (which StreamWeaver already has) is the right answer for server-to-browser push, and HTTP polling is fine for browser-to-agent communication. WebSockets would add complexity without benefit since the communication is asymmetric: the browser rarely sends to the server outside of form actions. This is the correct architecture, but the document should explicitly note *why* WebSockets were not chosen, since a reviewer will ask.
69
+
70
+ **Long-polling as an alternative to polling:** Instead of the agent polling `/deck/pending` every 1-2 seconds, the server could hold the connection open until a request arrives (long-polling). This eliminates latency entirely and reduces unnecessary HTTP requests. The implementation is slightly more complex but well-understood. Worth mentioning as a future optimization even if not implemented in Phase 3.
71
+
72
+ ---
73
+
74
+ ## 3. State Machine Complexity
75
+
76
+ ### The Concern: State Sprawl
77
+
78
+ The deck accumulates state from multiple sources:
79
+ - `state[:deck_selections]` -- slide_id -> option_label (core)
80
+ - `state[:deck_notes]` -- option-level notes (many keys)
81
+ - `state[:deck_generate]` -- generation status, timestamps
82
+ - `state[:_result]` -- submission payload
83
+ - Implicit state: current slide index (Alpine.js client-side), dirty tracking, layout override
84
+
85
+ This is spread across server session (cookie), client-side Alpine.js `x-data`, and localStorage. The document does not have a single "state map" showing where each piece of state lives and how they synchronize.
86
+
87
+ **What could go wrong:**
88
+ 1. **Cookie size limit.** The recommendation says "start with server session, upgrade if needed." But `deck_notes` is variable-length user input. If each of 10 slides has a 200-character note, plus option notes, you can easily hit 4KB. I would recommend starting with (B) file-backed state from day one -- it is not significantly harder and avoids a mid-stream migration.
89
+
90
+ 2. **Stale state after SSE push.** When a new option arrives via SSE, the client DOM updates but does the Alpine.js reactive state update? The option count changes, the selection set might need resetting, the summary slide's "Still need" list changes. The document says "needs validation" for Alpine + SSE integration (Section 4.12 in components.md) but the architecture should not leave this as a "maybe it works" -- it is load-bearing.
91
+
92
+ 3. **Dirty tracking across server and client.** The original pi-design-deck tracks dirty state entirely client-side (localStorage). The architecture routes through server sessions. If the user modifies a note, that is a POST to the server, a session update, and then the client needs to know "saved at HH:MM." This round-trip for every keystroke is either chatty or requires debouncing, which the document does not specify.
93
+
94
+ **Recommendation:** Create a state ownership table in the document:
95
+
96
+ | State | Owner | Sync Mechanism |
97
+ |-------|-------|---------------|
98
+ | Current slide index | Client (Alpine) | None needed |
99
+ | Selections | Client (Alpine) + Server (session) | POST on change |
100
+ | Notes | Client (Alpine) | POST on blur/debounce |
101
+ | Generate status | Server | SSE push to client |
102
+ | Dirty flag | Client | Computed from last-save timestamp |
103
+ | Layout override | Client (localStorage) | None needed |
104
+
105
+ ---
106
+
107
+ ## 4. Component Count: 50 Components
108
+
109
+ ### Assessment: Slightly High But Defensible
110
+
111
+ The inventory lists approximately 50 components (9 shared, 10 deck, 19 explainer, 12 enhanced existing). This is a lot, but the breakdown reveals that many are small:
112
+
113
+ - **Genuinely complex:** Mermaid (zoom engine), SlideContainer (two modes), DesignDeck (orchestrator), SidebarToc (scroll spy), GenerateMoreControls (state machine)
114
+ - **Medium:** CodeBlock, Chart, DataTable, DeckSummary, HtmlExporter
115
+ - **Simple (CSS wrapper + div):** VeCard, Callout, Prose, Pullquote, HeroSection, Legend, FlowArrow, DirTree, SkeletonPlaceholder, ConfirmationBar, CloseOverlay, LayoutToggle, Pipeline, Comparison
116
+
117
+ ### Components That Should Be Merged
118
+
119
+ 1. **`VeCard` and `Card`**: The document argues against merging because "Card has header/body/footer sub-components." But `VeCard` is just Card with a `depth:` option and no sub-components. Consider adding `depth:` to the existing Card and using it without sub-components. Two card types will confuse agent prompt engineering ("when do I use `card` vs `ve_card`?").
120
+
121
+ 2. **`DataTable` and `Table`**: Same argument. The document says they "serve different use cases" but the DSL distinction (`table` vs `data_table`) will confuse agents. Better: enhance `Table` with the sticky/hover/scrollable options and keep one component name. The different input formats (positional, file, headers+rows) can coexist.
122
+
123
+ 3. **`code_file` (from components.md 3.9) and `code_block`**: The document already implicitly merged these (code_block has a `file:` option). Good. Just make sure components.md is updated to reflect this.
124
+
125
+ 4. **`ProgressIndicator` and `progress_bar`**: The existing `progress_bar` with a `position: :fixed` variant seems sufficient. Adding a new name for what is visually the same element creates confusion.
126
+
127
+ ### Components That Might Be Missing
128
+
129
+ 1. **`Tabs` for explainer pages** -- multi-section pages where the user switches between views (e.g., "By File" vs "By Severity" in a diff review). StreamWeaver has tabs, but are they compatible with the explainer's use patterns?
130
+
131
+ 2. **`Badge` variants for status in data tables** -- the document mentions "status badges rendered as styled spans" but does not define how the agent specifies them within row data. The `{ status: :match, label: "Match" }` hash syntax in the DataTable example needs a rendering rule.
132
+
133
+ 3. **`Tooltip`** -- the deck has `description:` on options that is described as "hover text." How is this rendered? A native `title` attribute, or a styled tooltip component?
134
+
135
+ ---
136
+
137
+ ## 5. Five-Phase Implementation Sequencing
138
+
139
+ ### Phase 1 (Shared Foundation) -- Correct
140
+
141
+ Building shared components first is the right call. No notes.
142
+
143
+ ### Phase 2 (Design Deck Core) -- Correct but Large
144
+
145
+ Phase 2 is 6 items but includes the `DesignDeck` orchestrator, which is the single most complex piece. The risk is that it takes longer than estimated and delays everything after it. Consider splitting Phase 2 into:
146
+ - **2a:** SlideContainer (:swap mode) + ProgressIndicator + keyboard nav -- these are useful independently
147
+ - **2b:** DesignDeck + DeckSlide + DeckOption + selection state
148
+ - **2c:** DeckSummary
149
+
150
+ This lets you validate slide navigation before coupling it to the deck's selection logic.
151
+
152
+ ### Phase 3 (Generate-More Loop) -- Correct Placement
153
+
154
+ Separating generate-more from deck core is wise. The deck is useful without generate-more. Ship Phase 2 and get user feedback before investing in the polling infrastructure.
155
+
156
+ ### Phase 4 (Visual Explainer Core) -- Hidden Dependency
157
+
158
+ Phase 4 depends on the `HtmlExporter` from Phase 1. But the explainer also needs the *static export* path to be working end-to-end (write file, open in browser). This is a thin integration test but it should be called out: Phase 4 cannot be validated without a working export pipeline.
159
+
160
+ ### Phase 5 (Polish) -- Too Much in One Phase
161
+
162
+ Phase 5 is a grab bag of 9 items with wildly different effort levels (ModelSelector: medium, FlowArrow: small, Animation choreography: medium, Skill entry points: medium). Consider splitting:
163
+ - **5a:** Typography and utility components (Prose, Pullquote, DirTree, etc.) -- small, can be done in parallel
164
+ - **5b:** ModelSelector + Save/Load + Animation -- medium, interdependent with deck workflow
165
+ - **5c:** Skill entry points -- this is really Phase 6, since it depends on everything else being stable
166
+
167
+ ### Missing Phase: Integration Testing
168
+
169
+ There is no phase for end-to-end validation. After Phase 2, someone should write a real design deck script and test the full flow: write script, run it, make selections, submit, read result. After Phase 4, someone should generate a real diff review page. These integration checkpoints should be explicit.
170
+
171
+ ---
172
+
173
+ ## 6. Open Questions Evaluation
174
+
175
+ ### Q1 (Deck State: Server vs. Client) -- Disagree with Recommendation
176
+
177
+ The recommendation is "start with server session (A), upgrade if needed." As noted in Section 3 above, I think file-backed state (B) should be the starting point. The cost is minimal (write JSON to a temp file, read it back) and avoids the cookie-size cliff. Cookie-based session is fine for StreamWeaver's typical use (small form state), but the deck's state profile is different: variable-length user-generated notes make cookie overflow a when-not-if issue.
178
+
179
+ ### Q2 (Adapter Extension) -- Agree
180
+
181
+ The hybrid approach (adapter for interactive, self-render for display) is pragmatic and matches the existing codebase. Good call.
182
+
183
+ ### Q3 (Polling vs. Callback) -- Agree with Caveat
184
+
185
+ Polling is fine. Add long-polling as a documented future optimization path. Also document the poll interval as configurable (default 1s, adjustable for low-latency use cases).
186
+
187
+ ### Q4 (Deck as App Subclass) -- Agree
188
+
189
+ DSL methods on App is correct. The deck is a component composition, not a new application type. The conditional route registration is a minor wart but far less painful than a class hierarchy.
190
+
191
+ ### Q5 (DisplayDSL vs. App) -- Agree
192
+
193
+ Display components in DisplayDSL enables Feed-based push of rich content. This is exactly right for generate-more.
194
+
195
+ ### Q6 (Mermaid Re-rendering) -- Agree
196
+
197
+ Calling `mermaid.run()` after SSE insertion is the simplest approach. MutationObserver adds complexity and is harder to debug. One note: ensure that `mermaid.run({ nodes: [newElement] })` scopes the re-render to the new element only, not the entire page. Full-page re-render on every SSE push would cause visible flicker on existing diagrams.
198
+
199
+ ### Q7 (Anti-Slop) -- Agree
200
+
201
+ Documentation-only is correct for now. Theme presets are the enforcement mechanism. If slop becomes a problem, the fix is better prompts, not runtime CSS policing.
202
+
203
+ ### Q8 (Comparison Block Syntax) -- Agree
204
+
205
+ Named blocks (`before`/`after`) are the most readable. This matches existing StreamWeaver patterns.
206
+
207
+ ### Q9 (Explainer Slash Commands) -- Partially Disagree
208
+
209
+ The recommendation is (B) initially, (A) eventually. I agree with starting outside StreamWeaver, but I think (C) Claude Code custom commands is the better initial home, not standalone scripts. Custom commands are already the agent integration point -- they live in the project, they are discoverable, and they naturally separate data-gathering (agent-side) from rendering (StreamWeaver-side). Standalone scripts have no discoverability and will drift.
210
+
211
+ ---
212
+
213
+ ## 7. Scalability Concerns
214
+
215
+ ### 20-Slide Deck
216
+
217
+ The design is implicitly optimized for 3-8 slides (the typical design-decision deck). At 20 slides:
218
+ - **Cookie overflow:** Near-certain with server session state. File-backed state is essential.
219
+ - **Summary slide:** 20 summary cards in a grid will be visually overwhelming. Consider pagination or grouping.
220
+ - **Navigation:** Linear Back/Next through 20 slides is tedious. Consider adding a slide picker (dropdown or thumbnail strip) as a navigation shortcut.
221
+ - **Memory:** 20 slides with Mermaid diagrams each means 20 Mermaid render calls. Mermaid.js is not lightweight -- each render involves SVG generation. Lazy rendering (only render the active slide's diagrams) would help.
222
+
223
+ ### 500-File Diff Review
224
+
225
+ This is the real scalability stress test. A diff review with 500 changed files means:
226
+ - **SidebarToc:** 500 entries in the sidebar TOC is unusable. Need grouping by directory or category, with collapsible sections.
227
+ - **IntersectionObserver:** 500 observed elements could cause performance issues on scroll. Batch observation, use a single observer with root margin, or virtualize.
228
+ - **Page weight:** 500 code blocks with Prism.js highlighting is a lot of DOM. Consider pagination (show 20 files at a time with "load more") or virtual scrolling.
229
+ - **HTML export:** A self-contained HTML file with 500 highlighted code blocks could be 5-10MB. This may be fine for local viewing but brutal for Vercel deployment.
230
+ - **Generation time:** The agent generating 500 file reviews is already slow. But the *rendering* should not add to the pain. Ensure the DSL-to-HTML path is O(n) and does not have quadratic behaviors (e.g., repeated CSS generation per component).
231
+
232
+ **Recommendation:** Add a "Scale Considerations" section to the architecture document. Define soft limits (recommended: up to 10 slides, up to 50 files) and hard limits (tested: up to 20 slides, up to 200 files). For beyond-limits use cases, document the degradation strategy (pagination, grouping, lazy loading).
233
+
234
+ ### CDN Latency
235
+
236
+ The document notes "CDN latency is acceptable" for a local dev tool. True for first load, but Mermaid.js alone is ~2MB. If the user has a cold cache or is offline (airplane, VPN tunnel), the page will be broken. Consider:
237
+ - A local fallback for the most critical CDN assets (Mermaid, Prism)
238
+ - A "pre-warm" step that downloads CDN assets on gem install
239
+ - Graceful degradation: show raw code/text if Prism/Mermaid fail to load
240
+
241
+ ---
242
+
243
+ ## 8. Missing Features
244
+
245
+ Comparing the overlap analysis against the architecture:
246
+
247
+ ### Covered Well
248
+ - Mermaid rendering (both modes)
249
+ - Code highlighting
250
+ - Theme system
251
+ - Keyboard shortcuts
252
+ - HTML export
253
+ - Slide navigation (both modes)
254
+ - Selection and generate-more
255
+ - All major explainer components
256
+
257
+ ### Missing or Under-Specified
258
+
259
+ 1. **Heartbeat/Watchdog (from pi-design-deck Section 2.10):** The original deck has a 5-second heartbeat with 60-second grace period and idle timer. The architecture mentions none of this. If the browser tab is closed or the network drops, the agent script should know. StreamWeaver's existing SSE could serve as the heartbeat (connection drop = client gone), but this needs to be explicit.
260
+
261
+ 2. **Touch/Swipe Navigation (from visual-explainer):** The overlap analysis lists touch swipe support. The architecture mentions `keyboard_nav` but not touch. For scroll-snap mode, CSS handles the basic case, but the 50px swipe threshold and explicit touch handling from the explainer are not covered.
262
+
263
+ 3. **Accessibility (ARIA):** The DeckOption section mentions `role="radio"` and `aria-checked`, which is good. But the rest of the architecture is silent on accessibility. The slide container needs `aria-live` for slide transitions. The sidebar TOC needs `aria-current`. The generate-more skeleton needs `aria-busy`. Add an "Accessibility Requirements" subsection.
264
+
265
+ 4. **Auto-Trigger on Complex Tables (from visual-explainer Section 3.1):** This agent-side behavior (automatically rendering tables with 4+ rows as HTML) is not addressed. It is agent logic, not StreamWeaver logic, but the skill entry point should at least accept a flag like `auto_visual: true` that tells the rendering to upgrade tables.
266
+
267
+ 5. **Vercel Deployment / Share (from visual-explainer Section 3.6):** Mentioned in the overlap analysis but absent from the architecture. Even if it is out of scope for initial phases, it should be listed as a future extension.
268
+
269
+ 6. **`beforeunload` Handler:** The original deck sends a beacon on tab close. This is important for clean shutdown of `run_once!`. The architecture relies on `run_once!` blocking until submit, but what if the user closes the tab without submitting? The agent script would hang indefinitely. Need a cancellation path.
270
+
271
+ 7. **Double-Submit Prevention:** The original deck prevents double-submit on the summary slide. Not mentioned in the architecture.
272
+
273
+ 8. **surf-cli Image Generation:** The optional Gemini-powered image generation from visual-explainer. This is clearly out of scope for initial implementation, but worth listing as a future integration point.
274
+
275
+ ---
276
+
277
+ ## 9. Risk Assessment
278
+
279
+ ### Biggest Risk: Generate-More Loop Complexity
280
+
281
+ The generate-more loop is the riskiest feature. It introduces:
282
+ - Bidirectional communication between three parties (browser, server, agent)
283
+ - A long-running agent process with a polling thread
284
+ - Race conditions between user navigation and async option delivery
285
+ - Timeout handling across two processes
286
+ - DOM manipulation of content that contains embedded JavaScript (Mermaid init)
287
+
288
+ This feature alone accounts for ~20% of the estimated effort and contains the highest density of edge cases. If any single feature needs a spike/prototype before committing to the design, it is this one.
289
+
290
+ **Mitigation:** Phase 3 is correctly separated from Phase 2. Ship the deck without generate-more first. Validate the core selection/submission flow. Then tackle generate-more as a separate effort with its own spike.
291
+
292
+ ### Most Likely to Need Rework: State Management
293
+
294
+ The hybrid state approach (server session + client Alpine + localStorage) will accumulate inconsistencies. The most likely rework scenario: discovering mid-implementation that cookie-based sessions cannot hold deck state, requiring a migration to file-backed state that touches every route handler.
295
+
296
+ **Mitigation:** Start with file-backed state (recommendation above). Also, centralize state access behind a `DeckState` object that abstracts the storage backend.
297
+
298
+ ### Second Most Likely Rework: CSS Architecture
299
+
300
+ 50 components means a large CSS surface area. The document plans to add visual skills CSS as additional sections in `StreamWeaver::CSS`. But there is no mention of:
301
+ - CSS naming convention (BEM? `sw-` prefix?)
302
+ - Specificity management (what happens when depth-tier styles conflict with card styles?)
303
+ - CSS custom property namespacing (the example uses `--sw-vs-*` which is good, but is this enforced?)
304
+
305
+ Without a CSS architecture, the 50 components will accumulate specificity conflicts and !important overrides.
306
+
307
+ **Mitigation:** Define a CSS convention in the architecture document. The `sw-` prefix is already used in examples (`sw-mermaid-wrap`, `sw-code-block`). Make this explicit and enforce it.
308
+
309
+ ### Lower but Non-Zero Risk: CDN Dependency
310
+
311
+ The architecture depends on four CDN-hosted libraries (Mermaid, Prism, Chart.js, Google Fonts). Any of these being down, rate-limited, or serving a breaking update will break the user experience. Mermaid.js in particular has had breaking changes between minor versions.
312
+
313
+ **Mitigation:** Pin CDN versions (already done: `mermaid@11`). Consider adding integrity hashes (`integrity="sha384-..."`) to CDN script tags. Document the offline degradation story.
314
+
315
+ ---
316
+
317
+ ## Summary of Recommendations
318
+
319
+ | # | Recommendation | Priority | Effort |
320
+ |---|---------------|----------|--------|
321
+ | 1 | Add JSON-over-HTTP API as secondary agent protocol | Low (Phase 5) | Small |
322
+ | 2 | Document agent process lifecycle (heartbeat, crash recovery, clean shutdown) | High | Doc only |
323
+ | 3 | Add CANCELLED, ERROR, PARTIAL states to generate-more state machine | High | Doc + Small code |
324
+ | 4 | Start with file-backed state instead of cookie session | High | Small |
325
+ | 5 | Create state ownership table (what lives where, how it syncs) | High | Doc only |
326
+ | 6 | Merge VeCard into Card (add `depth:` option) | Medium | Small |
327
+ | 7 | Merge DataTable into Table (add sticky/hover options) | Medium | Small |
328
+ | 8 | Split Phase 2 into 2a/2b/2c for incremental validation | Medium | Planning only |
329
+ | 9 | Add explicit integration test checkpoints between phases | Medium | Planning only |
330
+ | 10 | Add scalability section with soft/hard limits | Medium | Doc only |
331
+ | 11 | Address `beforeunload` / tab-close cancellation for `run_once!` | High | Small |
332
+ | 12 | Define CSS naming convention and specificity rules | Medium | Doc only |
333
+ | 13 | Add accessibility requirements subsection | Medium | Doc only |
334
+ | 14 | Spike the generate-more loop before committing to full implementation | High | Medium |
335
+
336
+ ### Bottom Line
337
+
338
+ The architecture is solid. The DSL-first approach, the reuse of existing StreamWeaver patterns, the phased implementation, and the component decomposition are all well-reasoned. The main risks are in the generate-more loop (complex distributed state) and state management (hybrid storage). Both can be mitigated by spiking early and centralizing state behind an abstraction. The component count is manageable if you merge the redundant pairs (VeCard/Card, DataTable/Table).
339
+
340
+ Ship Phase 1, spike generate-more in parallel, and validate the full deck flow end-to-end before investing in polish.
@@ -0,0 +1,209 @@
1
+ # DHH-Style Architecture Review: StreamWeaver Visual Skills
2
+
3
+ *Reviewed: 2026-03-12*
4
+ *Document under review: `docs/visual-skills/design/architecture.md`*
5
+
6
+ ---
7
+
8
+ ## Overall Assessment
9
+
10
+ This is a strong architecture document that mostly respects the existing codebase and resists the temptation to over-engineer. The DSL reads like Ruby, the flat namespace decision is correct, and the "DSL IS the API" philosophy is sound. The design deck DSL -- `design_deck`, `slide`, `option` -- composes beautifully and would feel natural to any Ruby developer. However, there are areas where the document drifts into enterprise architecture territory: too many component classes for what are essentially styled divs, a polling-based generate-more loop that should be simpler, and a directory tree that implies 40+ new files when half of them could be collapsed. The good bones are here, but the document needs a ruthless editing pass to separate what must exist from what merely could exist.
11
+
12
+ ---
13
+
14
+ ## Critical Issues
15
+
16
+ ### 1. The Component Explosion
17
+
18
+ The document proposes roughly 30 new component classes. Many of these are CSS variations, not behavioral differences:
19
+
20
+ - `VeCard` is a `Card` with a CSS class. The document even acknowledges this: "a simpler depth-styled container." That is not a new class -- that is a `card depth: :hero` option.
21
+ - `DataTable` is `Table` with `sticky_header: true`. Add the options to `Table`.
22
+ - `HeroSection` is a `div` with a CSS class.
23
+ - `Prose` is a `div` with `max-width` set.
24
+ - `Pullquote` is a `blockquote` with styling.
25
+ - `FlowArrow` is an SVG arrow.
26
+ - `Legend` is a list of colored dots with labels.
27
+
28
+ Every new class is a file to maintain, a DSL method to document, and a concept a developer must learn. The bar for "this deserves to be a Component subclass" should be: does it have meaningful behavior or state that a CSS class cannot express?
29
+
30
+ **Recommendation:** Collapse pure-display components into existing primitives with variant/class options. Reserve new classes for components with actual behavior (Mermaid, SlideContainer, DesignDeck, KeyboardShortcuts, CodeBlock, Comparison).
31
+
32
+ ### 2. Duplicate Table Implementations
33
+
34
+ Creating `DataTable` alongside `Table` is wrong. You already have a `Table` component. Extend it:
35
+
36
+ ```ruby
37
+ table headers: ["Risk", "Severity"], rows: [...],
38
+ sticky_header: true, alternating: true, scrollable: true
39
+ ```
40
+
41
+ Two table classes in the same component library is a maintenance nightmare and a source of developer confusion. "Should I use `table` or `data_table`?" is a question no one should have to ask.
42
+
43
+ ### 3. The Generate-More Polling Loop is Over-Engineered
44
+
45
+ Section 7 introduces a state machine with five states, a polling endpoint, a request queue, a thread in the agent script, timeout tracking, and skeleton replacement via SSE. This is a lot of machinery for "user clicks button, agent generates options, options appear."
46
+
47
+ The existing `Feed` + `Pushable` infrastructure already handles server-to-browser push. The missing piece is browser-to-agent signaling, and polling is the simplest answer -- fine. But the state machine diagram, the `deck_generate` state hash with six keys, and the explicit timeout handling are premature. Start with:
48
+
49
+ 1. User clicks Generate. POST goes to server. Server queues it.
50
+ 2. Agent polls, gets request, generates, pushes via Feed.
51
+ 3. Done.
52
+
53
+ Timeout? The browser shows a spinner. If nothing arrives, the user clicks again. No state machine needed. No `started_at` tracking. No client-side timeout logic. Build the complex version when the simple version proves insufficient.
54
+
55
+ ---
56
+
57
+ ## Improvements Needed
58
+
59
+ ### 4. The Deck Namespace is Correct but Inconsistent
60
+
61
+ The document says "flat namespace" then immediately creates `Components::Deck::*` with 10 classes. That is not flat. The deck subsystem deserves its own namespace -- that decision is sound. But call it what it is: a namespaced subsystem, not a flat namespace. The document's framing is misleading.
62
+
63
+ ### 5. Repeated Container Capture Pattern
64
+
65
+ The existing `App` class has this pattern repeated approximately 15 times:
66
+
67
+ ```ruby
68
+ parent_components = @components
69
+ @components = []
70
+ instance_eval(&block)
71
+ component.children = @components
72
+ @components = parent_components
73
+ ```
74
+
75
+ The document proposes adding more instances of this same pattern for `design_deck`, `slide`, `option`, `comparison`, etc. The `capture_children_then_append` and `with_container` private methods exist but are not consistently used. Every new container DSL method should use one of these two helpers, not inline the pattern again.
76
+
77
+ The `design_deck` method in Section 4.1 inlines the pattern. The `slide` method inlines it. The `option` method inlines it. Use `with_container` or `capture_children_then_append`:
78
+
79
+ ```ruby
80
+ def design_deck(title, **options, &block)
81
+ deck = Components::Deck::DesignDeck.new(title, **options)
82
+ with_container(deck, &block)
83
+ deck.children << Components::Deck::DeckSummary.new
84
+ deck.validate!
85
+ deck
86
+ end
87
+
88
+ def slide(id, title = nil, **options, &block)
89
+ raise "slide must be inside design_deck" unless @current_deck
90
+ capture_children_then_append(Components::Deck::DeckSlide.new(id, title, **options), &block)
91
+ end
92
+ ```
93
+
94
+ ### 6. DSL Method Naming Collisions
95
+
96
+ The document proposes adding `slide` and `option` as top-level DSL methods on `App`. These are extremely generic names. Today, `slide` might mean a deck slide. Tomorrow, someone wants a carousel slide or a presentation slide.
97
+
98
+ The existing codebase avoids this -- `tab` is scoped by `@current_tabs` context, `crumb` by `@current_breadcrumbs`. The document does include context checks (`raise "slide must be inside design_deck"`), which is good. But consider whether `deck_slide` and `deck_option` would be clearer in the DSL:
99
+
100
+ ```ruby
101
+ design_deck "Direction" do
102
+ deck_slide "arch", "Architecture" do
103
+ deck_option "Monolith" do ... end
104
+ end
105
+ end
106
+ ```
107
+
108
+ Actually, no. Within the `design_deck` block, the context is unambiguous. `slide` and `option` read better. The context checks are sufficient. Keep the short names. The DSL reads like prose, which is the goal.
109
+
110
+ ### 7. CDN Asset Declaration is Good, But the Method Name is Wrong
111
+
112
+ ```ruby
113
+ def cdn_assets
114
+ [:mermaid]
115
+ end
116
+ ```
117
+
118
+ This conflates the asset with its delivery mechanism. What if you later vendor these? Call it `required_assets` or `external_assets`. The component should declare what it needs, not how it is delivered.
119
+
120
+ ### 8. The Skill Entry Points are Premature
121
+
122
+ Section 6.5 proposes `DesignDeckSkill` and `VisualExplainerSkill` classes that accept structured data and generate Ruby DSL scripts. This is a code generator that generates code for a DSL. That is one layer of indirection too many.
123
+
124
+ The agent already writes Ruby. The DSL IS the API. Why would the agent pass structured data to a skill class that then generates the same Ruby the agent could have written directly? This only makes sense if the agent cannot write Ruby -- but the entire architecture assumes it can.
125
+
126
+ Kill the skill entry points. The DSL is the skill entry point.
127
+
128
+ ### 9. Theme Presets -- Good Concept, Watch the Scope
129
+
130
+ Nine presets is a lot for a first pass. Ship with two (one for deck, one for explainer). Add more when users ask. The preset mechanism itself is clean -- CSS custom properties via `theme_overrides` is the right approach.
131
+
132
+ ---
133
+
134
+ ## What Works Well
135
+
136
+ ### The DSL Reads Beautifully
137
+
138
+ Section 10's examples are genuinely pleasant to read. This is the gold standard:
139
+
140
+ ```ruby
141
+ design_deck "Component Library Direction" do
142
+ slide "palette", "Color Palette",
143
+ context: "Choose the color direction" do
144
+ option "Warm Earth Tones", recommended: true do
145
+ code_block <<~CSS, lang: "css"
146
+ :root { --primary: #c2825a; }
147
+ CSS
148
+ end
149
+ end
150
+ end
151
+ ```
152
+
153
+ That reads like a description of what should appear. An agent could write this. A human could read this. This is what good DSL design looks like.
154
+
155
+ ### The Visual Explainer Example (Section 10.2) is Excellent
156
+
157
+ The diff review page example composes cleanly. `hero_section`, `ve_card`, `callout`, `code_block`, `data_table` -- each call earns its place. The `sidebar_toc` with section IDs that match `ve_card` IDs is elegant implicit linking.
158
+
159
+ ### Flat Namespace for Shared Components
160
+
161
+ Correct decision. `mermaid` belongs next to `table` and `card`. No `VisualSkills::Components::Mermaid` namespace soup.
162
+
163
+ ### Design Deck as DSL Methods, Not a Subclass
164
+
165
+ Correct decision. `design_deck` is like `tabs` or `modal` -- a DSL method that composes children. No `DesignDeckApp < App` parallel hierarchy.
166
+
167
+ ### The Open Questions are Well-Reasoned
168
+
169
+ All nine recommendations are sound:
170
+
171
+ - **Q1 (Session storage):** Server-side session, overflow to file if needed. Correct. Do not prematurely optimize.
172
+ - **Q2 (Adapter extension):** Display components render themselves, interactive components use the adapter. This is already the implicit pattern -- making it explicit is good.
173
+ - **Q3 (Polling):** Simple polling wins. Correct.
174
+ - **Q4 (Not a subclass):** Correct, as noted above.
175
+ - **Q5 (DisplayDSL for shared components):** Correct. Feed push of mermaid diagrams is powerful.
176
+ - **Q6 (Mermaid re-rendering):** `mermaid.run({ nodes: [newElement] })` after DOM insertion. Simple and correct.
177
+ - **Q7 (Anti-slop):** Documentation only. Correct. Do not build a CSS linter.
178
+ - **Q8 (Comparison syntax):** Named blocks (`before`/`after`). Correct. Follows existing `trigger`/`menu` pattern.
179
+ - **Q9 (Slash commands outside gem):** Correct. Agent logic and rendering logic should not be coupled.
180
+
181
+ ### The Comparison Component DSL
182
+
183
+ ```ruby
184
+ comparison before_label: "Current", after_label: "Proposed" do
185
+ before { mermaid "..." }
186
+ after { mermaid "..." }
187
+ end
188
+ ```
189
+
190
+ This is clean and follows the established `dropdown` pattern with `trigger`/`menu`. Named blocks for multi-region components is the right idiom for this DSL.
191
+
192
+ ### HtmlExporter as Infrastructure, Not a Component
193
+
194
+ Correct separation. Export is a pipeline operation on the entire app, not a renderable component.
195
+
196
+ ---
197
+
198
+ ## Summary of Recommendations
199
+
200
+ 1. **Collapse CSS-only components** into existing primitives with options. Cut the class count by 40%.
201
+ 2. **Merge DataTable into Table.** One table class, more options.
202
+ 3. **Simplify the generate-more loop.** Kill the state machine. Queue, poll, push. Three steps.
203
+ 4. **Use `with_container`/`capture_children_then_append` consistently** in all new DSL methods. Do not inline the capture pattern again.
204
+ 5. **Rename `cdn_assets` to `required_assets`.**
205
+ 6. **Kill the Skill entry points.** The DSL is the API. The agent writes Ruby directly.
206
+ 7. **Ship two theme presets**, not nine. Add more when demanded.
207
+ 8. **Phase 1 is correctly prioritized.** Mermaid, CodeBlock, and theme enhancements unblock everything. Ship those first and let the rest follow from real usage.
208
+
209
+ The architecture is fundamentally sound. The DSL design is strong. The main risk is building too many small classes that each do too little. Ruby's power is in expressive, composable abstractions -- not in having a class for every visual concept. A `div` with a CSS class is still a `div`. Treat it that way.
@@ -0,0 +1,100 @@
1
+ # Design Evolution Log
2
+
3
+ ## Purpose
4
+ Track every design decision, iteration, and review so future LLMs (and humans)
5
+ can understand WHY the architecture looks the way it does.
6
+
7
+ ---
8
+
9
+ ## Entry 1: Analysis Phase Complete (2026-03-12)
10
+
11
+ ### What we learned
12
+ - **37% overlap confirmed** — user predicted ~1/3, analysis yielded 37%
13
+ - **Token savings are asymmetric:** deck saves 30-45%, explainer saves 80-85%
14
+ - **The explainer's savings are architectural:** 30K tokens of design system in the prompt → 0 in framework code
15
+ - **50 components identified:** 9 shared, 10 deck, 19 explainer, 12 existing enhancements
16
+
17
+ ### Decisions made
18
+ 1. Analysis-first approach validated — parallel subagents with shared template produced consistent, comparable output
19
+ 2. Gherkin as bridge format — 1003 lines of scenarios, detailed enough for implementation
20
+ 3. 5-phase implementation sequence confirmed (shared → deck → explainer → polish → integration)
21
+
22
+ ### Key risks identified
23
+ 1. **Generate-more loop** is the hardest architectural challenge — Promise-based blocking in Pi doesn't map to StreamWeaver's reactive model
24
+ 2. **Agent communication protocol** is bidirectional — agent needs to both send data (create deck) and receive results (user selections)
25
+ 3. **CSS complexity** — visual-explainer has 40+ CSS components, 13 font pairings, 5 color palettes. Quality bar is high.
26
+
27
+ ---
28
+
29
+ ## Entry 2: OO Design Phase (2026-03-12, in progress)
30
+
31
+ ### Design agent launched with:
32
+ - All 6 analysis artifacts as input
33
+ - 16 existing StreamWeaver source files for pattern matching
34
+ - Explicit instruction to be opinionated and flag genuine trade-offs
35
+ - Required outputs: module structure, class hierarchies, data flow diagrams, DSL examples
36
+
37
+ ### Reviews completed:
38
+ - [x] DHH reviewer — "fundamentally sound, needs ruthless editing pass"
39
+ - [x] Codex second opinion — "solid, spike generate-more, file-backed state"
40
+ - [ ] User review of progression before implementation
41
+
42
+ ---
43
+
44
+ ## Entry 4: Review Synthesis (2026-03-12)
45
+
46
+ ### Key outcomes from dual review
47
+ 1. **Component count reduced 50 → ~32** by merging CSS-only wrappers into existing primitives
48
+ 2. **State management changed** from cookie session to file-backed state (Codex convinced us)
49
+ 3. **Generate-more: spike first** — both reviewers had different concerns; a spike will reveal which matter
50
+ 4. **Skill entry points killed** — "the DSL IS the API" (DHH). Agent glue lives outside the gem as custom commands (Codex)
51
+ 5. **5 new doc sections needed**: state ownership table, CSS convention, accessibility, scalability limits, agent lifecycle
52
+
53
+ ### Where reviewers disagreed (and how we resolved)
54
+ - **State storage:** DHH said cookies, Codex said files → files (Codex is right about note overflow)
55
+ - **Generate-more complexity:** DHH said simpler, Codex said more states needed → spike it (both right from different angles)
56
+ - **Component count:** DHH said cut 40%, Codex said defensible → cut ~36% (DHH's instinct is right)
57
+
58
+ ### Revised component count: ~32 classes + ~7 CSS helpers = ~39 DSL methods
59
+
60
+ ---
61
+
62
+ ## Entry 5: Gemini Adversarial Review (2026-03-12)
63
+
64
+ ### Best insight: Push-to-state, not push-to-DOM
65
+ Gemini proposed that generate-more should push new options to server-side state and let
66
+ StreamWeaver's reactive re-render handle display, instead of pushing HTML snippets via SSE.
67
+ This aligns with StreamWeaver's existing model and solves the "phantom option" race condition
68
+ (user navigates away during generation). **Adopted as architecture change.**
69
+
70
+ ### Good catch: Session-scoped request queue
71
+ Generate requests queued on the server must be scoped to session ID, otherwise stale
72
+ requests from killed agent processes persist. Neither prior reviewer caught this.
73
+
74
+ ### Overruled: Token efficiency concern
75
+ Gemini argued DSL reference docs in agent context erode savings. Math doesn't support this:
76
+ ~3K DSL reference vs ~30K CSS patterns = still 80%+ net savings. Overruled.
77
+
78
+ ### Overruled: Component rot / plugin system
79
+ StreamWeaver is a bounded DSL, not a general-purpose UI framework. Component set is
80
+ intentionally focused. No plugin system needed.
81
+
82
+ ### Running tally of reviews: 3 reviewers, all approve core architecture
83
+ - DHH: "fundamentally sound" — cut components, simplify generate-more
84
+ - Codex: "solid" — spike generate-more, file-backed state, accessibility
85
+ - Gemini: "push-to-state is better" — best architectural improvement so far
86
+
87
+ ---
88
+
89
+ ## Entry 3: Blog Series Recognized (2026-03-12)
90
+
91
+ ### Insight
92
+ The process itself is generating multiple blog-worthy artifacts:
93
+ 1. **Token efficiency** — the flagship technical argument
94
+ 2. **Claude Code capabilities** — parallel analysis, quality of autonomous work
95
+ 3. **Engineering process + GenAI** — specification depth as the new 10x multiplier
96
+ 4. **Repeatable process** — skill extraction from a successful workflow
97
+
98
+ ### Decision
99
+ Track blog material as we go rather than reconstructing after the fact.
100
+ The process IS the content.