robot_lab 0.1.0 → 0.2.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/.architecture/AGENTS.md +32 -0
  3. data/.architecture/config.yml +8 -0
  4. data/.architecture/members.yml +60 -0
  5. data/.architecture/reviews/feature-free-will.md +490 -0
  6. data/.architecture/reviews/overall-codebase.md +427 -0
  7. data/.claude/settings.local.json +57 -0
  8. data/.codex/config.toml +2 -0
  9. data/.irbrc +2 -2
  10. data/.rubocop.yml +172 -0
  11. data/CHANGELOG.md +72 -0
  12. data/CLAUDE.md +139 -0
  13. data/README.md +91 -95
  14. data/Rakefile +109 -3
  15. data/agent2agent_review.md +192 -0
  16. data/agentf_improvements.md +253 -0
  17. data/agents.md +14 -0
  18. data/docs/examples/index.md +37 -2
  19. data/docs/getting-started/configuration.md +20 -7
  20. data/docs/guides/index.md +16 -16
  21. data/docs/guides/knowledge.md +7 -1
  22. data/docs/guides/observability.md +132 -0
  23. data/docs/index.md +30 -3
  24. data/docs/superpowers/plans/2026-05-06-agentskills.md +1303 -0
  25. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +247 -0
  26. data/examples/.envrc +1 -0
  27. data/examples/01_simple_robot.rb +5 -9
  28. data/examples/02_tools.rb +5 -9
  29. data/examples/03_network.rb +8 -9
  30. data/examples/04_mcp.rb +21 -29
  31. data/examples/05_streaming.rb +12 -18
  32. data/examples/06_prompt_templates.rb +11 -19
  33. data/examples/07_network_memory.rb +16 -31
  34. data/examples/08_llm_config.rb +10 -22
  35. data/examples/09_chaining.rb +16 -27
  36. data/examples/10_memory.rb +12 -28
  37. data/examples/11_network_introspection.rb +15 -29
  38. data/examples/12_message_bus.rb +5 -12
  39. data/examples/13_spawn.rb +5 -10
  40. data/examples/14_rusty_circuit/.envrc +1 -0
  41. data/examples/14_rusty_circuit/comic.rb +2 -0
  42. data/examples/14_rusty_circuit/heckler.rb +1 -1
  43. data/examples/14_rusty_circuit/open_mic.rb +1 -3
  44. data/examples/14_rusty_circuit/scout.rb +2 -0
  45. data/examples/15_memory_network_and_bus/.envrc +1 -0
  46. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +6 -3
  47. data/examples/15_memory_network_and_bus/linux_writer.rb +1 -1
  48. data/examples/15_memory_network_and_bus/output/combined_article.md +6 -6
  49. data/examples/15_memory_network_and_bus/output/final_article.md +6 -8
  50. data/examples/15_memory_network_and_bus/output/linux_draft.md +4 -2
  51. data/examples/15_memory_network_and_bus/output/mac_draft.md +3 -3
  52. data/examples/15_memory_network_and_bus/output/memory.json +6 -6
  53. data/examples/15_memory_network_and_bus/output/revision_1.md +10 -11
  54. data/examples/15_memory_network_and_bus/output/revision_2.md +6 -8
  55. data/examples/15_memory_network_and_bus/output/windows_draft.md +3 -3
  56. data/examples/16_writers_room/.envrc +1 -0
  57. data/examples/16_writers_room/writers_room.rb +2 -4
  58. data/examples/17_skills.rb +8 -17
  59. data/examples/18_rails/Gemfile +1 -0
  60. data/examples/19_token_tracking.rb +9 -15
  61. data/examples/20_circuit_breaker.rb +10 -19
  62. data/examples/21_learning_loop.rb +11 -20
  63. data/examples/22_context_compression.rb +6 -13
  64. data/examples/23_convergence.rb +6 -17
  65. data/examples/24_structured_delegation.rb +11 -15
  66. data/examples/25_history_search.rb +5 -12
  67. data/examples/26_document_store.rb +6 -13
  68. data/examples/27_incident_response/incident_response.rb +4 -5
  69. data/examples/28_mcp_discovery.rb +8 -11
  70. data/examples/29_ractor_tools.rb +4 -9
  71. data/examples/30_ractor_network.rb +10 -19
  72. data/examples/31_launch_assessment.rb +10 -23
  73. data/examples/32_newsletter_reader.rb +188 -0
  74. data/examples/33_stock_generator.rb +80 -0
  75. data/examples/33_stock_predictor.rb +306 -0
  76. data/examples/34_agentskills.rb +72 -0
  77. data/examples/README.md +1 -1
  78. data/examples/common.rb +76 -0
  79. data/examples/ruboruby.md +423 -0
  80. data/examples/temp.md +51 -0
  81. data/lib/robot_lab/agent_skill.rb +63 -0
  82. data/lib/robot_lab/agent_skill_catalog.rb +74 -0
  83. data/lib/robot_lab/ask_user.rb +2 -2
  84. data/lib/robot_lab/bus_poller.rb +12 -5
  85. data/lib/robot_lab/config.rb +1 -12
  86. data/lib/robot_lab/delegation_future.rb +1 -1
  87. data/lib/robot_lab/doom_loop_detector.rb +98 -0
  88. data/lib/robot_lab/history_compressor.rb +4 -10
  89. data/lib/robot_lab/mcp/client.rb +1 -2
  90. data/lib/robot_lab/mcp/connection_poller.rb +3 -3
  91. data/lib/robot_lab/mcp/server.rb +1 -1
  92. data/lib/robot_lab/mcp/server_discovery.rb +0 -2
  93. data/lib/robot_lab/memory.rb +32 -27
  94. data/lib/robot_lab/memory_change.rb +2 -2
  95. data/lib/robot_lab/message.rb +4 -4
  96. data/lib/robot_lab/network.rb +11 -6
  97. data/lib/robot_lab/robot/agent_skill_matching.rb +99 -0
  98. data/lib/robot_lab/robot/bus_messaging.rb +9 -27
  99. data/lib/robot_lab/robot/history_search.rb +4 -1
  100. data/lib/robot_lab/robot/mcp_management.rb +5 -11
  101. data/lib/robot_lab/robot/template_rendering.rb +60 -40
  102. data/lib/robot_lab/robot.rb +323 -206
  103. data/lib/robot_lab/robot_result.rb +6 -5
  104. data/lib/robot_lab/run_config.rb +5 -11
  105. data/lib/robot_lab/script_tool.rb +76 -0
  106. data/lib/robot_lab/state_proxy.rb +7 -5
  107. data/lib/robot_lab/tool.rb +3 -3
  108. data/lib/robot_lab/tool_config.rb +1 -1
  109. data/lib/robot_lab/tool_manifest.rb +5 -7
  110. data/lib/robot_lab/user_message.rb +2 -2
  111. data/lib/robot_lab/version.rb +1 -1
  112. data/lib/robot_lab/waiter.rb +1 -1
  113. data/lib/robot_lab.rb +41 -52
  114. data/logfile +8 -0
  115. data/mkdocs.yml +2 -3
  116. data/robot_concurrency.md +38 -0
  117. data/simple_acp_review.md +298 -0
  118. data/site/404.html +2300 -0
  119. data/site/api/core/index.html +2706 -0
  120. data/site/api/core/memory/index.html +3793 -0
  121. data/site/api/core/network/index.html +3500 -0
  122. data/site/api/core/robot/index.html +4566 -0
  123. data/site/api/core/state/index.html +3390 -0
  124. data/site/api/core/tool/index.html +3843 -0
  125. data/site/api/index.html +2635 -0
  126. data/site/api/mcp/client/index.html +3435 -0
  127. data/site/api/mcp/index.html +2783 -0
  128. data/site/api/mcp/server/index.html +3252 -0
  129. data/site/api/mcp/transports/index.html +3352 -0
  130. data/site/api/messages/index.html +2641 -0
  131. data/site/api/messages/text-message/index.html +3087 -0
  132. data/site/api/messages/tool-call-message/index.html +3159 -0
  133. data/site/api/messages/tool-result-message/index.html +3252 -0
  134. data/site/api/messages/user-message/index.html +3212 -0
  135. data/site/api/streaming/context/index.html +3282 -0
  136. data/site/api/streaming/events/index.html +3347 -0
  137. data/site/api/streaming/index.html +2738 -0
  138. data/site/architecture/core-concepts/index.html +3757 -0
  139. data/site/architecture/index.html +2797 -0
  140. data/site/architecture/message-flow/index.html +3238 -0
  141. data/site/architecture/network-orchestration/index.html +3433 -0
  142. data/site/architecture/robot-execution/index.html +3140 -0
  143. data/site/architecture/state-management/index.html +3498 -0
  144. data/site/assets/css/custom.css +56 -0
  145. data/site/assets/images/favicon.png +0 -0
  146. data/site/assets/images/robot_lab.jpg +0 -0
  147. data/site/assets/javascripts/bundle.79ae519e.min.js +16 -0
  148. data/site/assets/javascripts/bundle.79ae519e.min.js.map +7 -0
  149. data/site/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
  150. data/site/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
  151. data/site/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
  152. data/site/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
  153. data/site/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
  154. data/site/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
  155. data/site/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
  156. data/site/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
  157. data/site/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
  158. data/site/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
  159. data/site/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
  160. data/site/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
  161. data/site/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
  162. data/site/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
  163. data/site/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
  164. data/site/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
  165. data/site/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
  166. data/site/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
  167. data/site/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
  168. data/site/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
  169. data/site/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
  170. data/site/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
  171. data/site/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
  172. data/site/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
  173. data/site/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
  174. data/site/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
  175. data/site/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
  176. data/site/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
  177. data/site/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
  178. data/site/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
  179. data/site/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
  180. data/site/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
  181. data/site/assets/javascripts/lunr/tinyseg.js +206 -0
  182. data/site/assets/javascripts/lunr/wordcut.js +6708 -0
  183. data/site/assets/javascripts/workers/search.2c215733.min.js +42 -0
  184. data/site/assets/javascripts/workers/search.2c215733.min.js.map +7 -0
  185. data/site/assets/stylesheets/main.484c7ddc.min.css +1 -0
  186. data/site/assets/stylesheets/main.484c7ddc.min.css.map +1 -0
  187. data/site/assets/stylesheets/palette.ab4e12ef.min.css +1 -0
  188. data/site/assets/stylesheets/palette.ab4e12ef.min.css.map +1 -0
  189. data/site/concepts/index.html +3455 -0
  190. data/site/examples/basic-chat/index.html +2880 -0
  191. data/site/examples/index.html +2907 -0
  192. data/site/examples/mcp-server/index.html +3018 -0
  193. data/site/examples/multi-robot-network/index.html +3131 -0
  194. data/site/examples/rails-application/index.html +3329 -0
  195. data/site/examples/tool-usage/index.html +3085 -0
  196. data/site/getting-started/configuration/index.html +3745 -0
  197. data/site/getting-started/index.html +2572 -0
  198. data/site/getting-started/installation/index.html +2981 -0
  199. data/site/getting-started/quick-start/index.html +2942 -0
  200. data/site/guides/building-robots/index.html +4290 -0
  201. data/site/guides/creating-networks/index.html +3858 -0
  202. data/site/guides/index.html +2586 -0
  203. data/site/guides/mcp-integration/index.html +3581 -0
  204. data/site/guides/memory/index.html +3586 -0
  205. data/site/guides/rails-integration/index.html +4019 -0
  206. data/site/guides/streaming/index.html +3157 -0
  207. data/site/guides/using-tools/index.html +3802 -0
  208. data/site/index.html +2671 -0
  209. data/site/search/search_index.json +1 -0
  210. data/site/sitemap.xml +183 -0
  211. data/site/sitemap.xml.gz +0 -0
  212. data/site/tags.json +1 -0
  213. data/temp.md +6 -0
  214. data/tool_manifest_plan.md +155 -0
  215. metadata +154 -92
  216. data/docs/examples/rails-application.md +0 -419
  217. data/docs/guides/ractor-parallelism.md +0 -364
  218. data/docs/guides/rails-integration.md +0 -681
  219. data/docs/superpowers/plans/2026-04-14-ractor-integration.md +0 -1538
  220. data/docs/superpowers/specs/2026-04-14-ractor-integration-design.md +0 -258
  221. data/lib/generators/robot_lab/install_generator.rb +0 -90
  222. data/lib/generators/robot_lab/job_generator.rb +0 -40
  223. data/lib/generators/robot_lab/robot_generator.rb +0 -55
  224. data/lib/generators/robot_lab/templates/initializer.rb.tt +0 -42
  225. data/lib/generators/robot_lab/templates/job.rb.tt +0 -21
  226. data/lib/generators/robot_lab/templates/migration.rb.tt +0 -32
  227. data/lib/generators/robot_lab/templates/result_model.rb.tt +0 -52
  228. data/lib/generators/robot_lab/templates/robot.rb.tt +0 -31
  229. data/lib/generators/robot_lab/templates/robot_job.rb.tt +0 -18
  230. data/lib/generators/robot_lab/templates/robot_test.rb.tt +0 -34
  231. data/lib/generators/robot_lab/templates/routing_robot.rb.tt +0 -59
  232. data/lib/generators/robot_lab/templates/thread_model.rb.tt +0 -40
  233. data/lib/robot_lab/document_store.rb +0 -155
  234. data/lib/robot_lab/ractor_boundary.rb +0 -42
  235. data/lib/robot_lab/ractor_job.rb +0 -37
  236. data/lib/robot_lab/ractor_memory_proxy.rb +0 -85
  237. data/lib/robot_lab/ractor_network_scheduler.rb +0 -154
  238. data/lib/robot_lab/ractor_worker_pool.rb +0 -117
  239. data/lib/robot_lab/rails_integration/engine.rb +0 -29
  240. data/lib/robot_lab/rails_integration/job.rb +0 -158
  241. data/lib/robot_lab/rails_integration/railtie.rb +0 -51
  242. data/lib/robot_lab/rails_integration/turbo_stream_callbacks.rb +0 -72
@@ -0,0 +1,427 @@
1
+ # Architecture Review: Overall Codebase
2
+
3
+ **Date**: 2026-02-16
4
+ **Review Type**: Comprehensive Codebase Review
5
+ **Version**: 0.0.5 (branch: `free_will`)
6
+ **Reviewers**: Systems Architect, Concurrency Specialist, API Design Lead, Reliability Engineer, Testing Strategist, Pragmatic Enforcer
7
+
8
+ ## Executive Summary
9
+
10
+ RobotLab is a well-structured Ruby framework for orchestrating multi-robot LLM workflows. At ~5,000 lines of source code with ~5,400 lines of tests, it demonstrates strong engineering discipline. The architecture cleanly separates concerns into Robot (agent), Network (orchestration), Memory (state), and MCP (external tools), with TypedBus providing async inter-robot messaging.
11
+
12
+ The codebase shows thoughtful design decisions: hierarchical configuration resolution, reactive memory with pub/sub semantics, and a clean delegation pattern to RubyLLM. However, there are areas where the architecture is stretched -- the streaming subsystem is declared but not wired into execution, the `NetworkRun` class referenced in CLAUDE.md appears to have been removed without updating docs, and some concurrency patterns could lead to subtle issues under load.
13
+
14
+ **Overall Assessment**: Adequate -- with targeted improvements, can reach Strong
15
+
16
+ **Key Findings**:
17
+ - Clean module decomposition with well-defined responsibilities per class
18
+ - Strong test coverage by line count (test:source ratio > 1:1)
19
+ - Concurrency model has known edge cases documented in MEMORY.md but not yet protected in core code
20
+ - Streaming events are fully defined but not integrated into Robot#run or Network#run
21
+ - Some dead abstractions (adapters directory referenced in test_helper but not in lib)
22
+
23
+ **Critical Actions**:
24
+ - Wire streaming context into Robot#run and Network#run, or remove the streaming module to avoid misleading API surface
25
+ - Add processing guards to Robot#run for async re-entrancy protection (documented in MEMORY.md but missing from core)
26
+ - Clarify Network execution model: `call_parallel` vs the documented sequential pipeline
27
+
28
+ ---
29
+
30
+ ## System Overview
31
+
32
+ ### File Counts
33
+ | Area | Files | Lines |
34
+ |------|-------|-------|
35
+ | Core lib (`lib/`) | 38 | ~5,050 |
36
+ | Tests (`test/`) | 26 | ~5,425 |
37
+ | Examples | 15+ scripts | N/A |
38
+
39
+ ### Dependency Graph (Core)
40
+
41
+ ```
42
+ RobotLab (module)
43
+ ├── Config (MywayConfig::Base)
44
+ │ └── configures RubyLLM + PromptManager
45
+ ├── Robot (RubyLLM::Agent)
46
+ │ ├── TemplateRendering (module)
47
+ │ ├── MCPManagement (module)
48
+ │ └── BusMessaging (module)
49
+ ├── Network
50
+ │ ├── SimpleFlow::Pipeline
51
+ │ ├── Task (step wrapper)
52
+ │ └── Memory (shared)
53
+ ├── Memory
54
+ │ ├── Waiter (ConditionVariable)
55
+ │ ├── StateProxy (method_missing)
56
+ │ ├── MemoryChange (notification)
57
+ │ └── RedisBackend (optional)
58
+ ├── MCP::Client
59
+ │ ├── MCP::Server (config)
60
+ │ └── Transports (Stdio, WebSocket, SSE, StreamableHTTP)
61
+ ├── Tool (RubyLLM::Tool)
62
+ │ ├── AskUser (built-in)
63
+ │ └── ToolManifest (registry)
64
+ ├── Message hierarchy
65
+ │ ├── TextMessage
66
+ │ ├── ToolCallMessage
67
+ │ ├── ToolResultMessage
68
+ │ └── UserMessage
69
+ ├── RobotMessage (Data.define, bus envelope)
70
+ ├── RobotResult (execution result)
71
+ ├── Streaming::Events (constants)
72
+ ├── Streaming::Context (event publisher)
73
+ └── Utils, Errors, ToolConfig
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Individual Member Reviews
79
+
80
+ ### Systems Architect - Principal Systems Architect
81
+
82
+ **Perspective**: Evaluates overall structure, module boundaries, and dependency flow
83
+
84
+ #### Key Observations
85
+ - Clean Zeitwerk autoloading with appropriate inflector overrides and ignores
86
+ - Robot concern extraction into `TemplateRendering`, `MCPManagement`, and `BusMessaging` modules is well-executed
87
+ - The `robot_lab.rb` entry point serves dual duty: Zeitwerk setup and module-level factory methods
88
+
89
+ #### Strengths
90
+ 1. **Hierarchical config resolution**: The `ToolConfig` module elegantly handles `:none`, `:inherit`, and explicit values across four levels (global > network > robot > runtime)
91
+ 2. **Single-responsibility classes**: Memory, StateProxy, Waiter, MemoryChange each have a clear purpose
92
+ 3. **Clean factory pattern**: `RobotLab.build()` and `RobotLab.create_network()` provide discoverable entry points
93
+ 4. **Zeitwerk hygiene**: Proper ignores for Rails integration, generators, and Robot concern modules
94
+
95
+ #### Concerns
96
+ 1. **Ghost references** (Impact: Medium)
97
+ - Issue: `NetworkRun` is referenced in CLAUDE.md, Robot#run signature, and MCPManagement (`network&.network&.mcp`) but the class doesn't exist in lib/. The `network:` parameter in `Robot#run` expects a `NetworkRun` but receives nil in practice because Network delegates to Task which delegates to Robot#call, not Robot#run directly.
98
+ - Recommendation: Audit `network:` parameter usage in Robot#run -- it appears vestigial. If NetworkRun was removed, clean up the parameter and the `network&.network` calls in MCPManagement.
99
+
100
+ 2. **Adapter directory mismatch** (Impact: Low)
101
+ - Issue: `test_helper.rb` references `'lib/robot_lab/adapters'` in SimpleCov groups, but no `adapters/` directory exists in the current codebase.
102
+ - Recommendation: Remove the stale SimpleCov group or restore the adapters directory if adapters are planned.
103
+
104
+ 3. **Eager loading at boot** (Impact: Medium)
105
+ - Issue: `loader.eager_load` (line 69 of robot_lab.rb) forces all classes to load at require time. For a gem, lazy loading is typically preferred -- eager loading is a Rails convention for avoiding autoloading in multi-threaded environments.
106
+ - Recommendation: Move `eager_load` behind a conditional (`if defined?(Rails)`) or remove it entirely, since Zeitwerk's lazy autoloading handles thread-safety correctly.
107
+
108
+ 4. **Streaming module is orphaned** (Impact: Medium)
109
+ - Issue: `Streaming::Events` and `Streaming::Context` define a rich event vocabulary (22 event types, lifecycle/delta/HITL categories) but nothing in Robot#run or Network#run publishes these events. The streaming subsystem exists as infrastructure without integration.
110
+ - Recommendation: Either wire streaming into the execution path (Robot#run emits `RUN_STARTED`/`TEXT_DELTA`/etc.) or clearly mark it as "planned" with appropriate documentation.
111
+
112
+ #### Recommendations
113
+ 1. **Audit and remove NetworkRun references** (Priority: High, Effort: Small)
114
+ 2. **Make eager_load conditional** (Priority: Medium, Effort: Small)
115
+ 3. **Integrate or defer streaming** (Priority: Medium, Effort: Large)
116
+
117
+ ---
118
+
119
+ ### Concurrency Specialist - Async & Concurrency Engineer
120
+
121
+ **Perspective**: Analyzes async patterns, race conditions, and message ordering guarantees
122
+
123
+ #### Key Observations
124
+ - Two concurrency models coexist: thread-based (Memory waiters) and fiber-based (Async for bus messaging)
125
+ - `dispatch_async` in Utils correctly checks `Async::Task.current?` before choosing execution strategy
126
+ - MEMORY.md documents the critical async re-entrancy bug but the fix is NOT implemented in core Robot class
127
+
128
+ #### Strengths
129
+ 1. **Waiter implementation is correct**: Uses Mutex + ConditionVariable with proper signaled flag to avoid missed wakeups. Timeout calculation uses monotonic-safe arithmetic.
130
+ 2. **Bus publish safety**: `publish_to_bus` correctly avoids double-wrapping in Async by checking `Async::Task.current?`
131
+ 3. **Memory thread-safety**: All Memory read/write operations are protected by `@mutex`
132
+
133
+ #### Concerns
134
+ 1. **Async re-entrancy in Robot#run** (Impact: High)
135
+ - Issue: When a robot's `run()` yields during HTTP I/O (via RubyLLM), the Async scheduler can switch to another fiber that delivers a bus message to the same robot. This calls `handle_message_via_llm` which calls `run()` again, inserting user messages between `tool_use`/`tool_result` pairs in `@chat`, corrupting Anthropic API ordering. This is documented in MEMORY.md but the processing guard is NOT in `Robot#run` or `BusMessaging#handle_incoming_delivery`.
136
+ - Recommendation: Add a `@processing` guard and `@queue` to Robot, serializing `run()` calls. The pattern from `examples/14_rusty_circuit/scout.rb` should be promoted to core.
137
+
138
+ 2. **dispatch_async Thread leak** (Impact: Medium)
139
+ - Issue: In `Utils#dispatch_async`, when NOT inside Async, it spawns a bare `Thread.new`. These threads are fire-and-forget with no join, no pool, and no lifecycle management. Under heavy subscription activity in Memory, this could create unbounded threads.
140
+ - Recommendation: Use a thread pool (e.g., `Concurrent::FixedThreadPool` from concurrent-ruby) or require Async for reactive features.
141
+
142
+ 3. **Memory#set + notify is not atomic** (Impact: Medium)
143
+ - Issue: `Memory#set` stores the value inside `@mutex.synchronize`, then releases the mutex before calling `wake_waiters` and `notify_subscribers_async`. Between the mutex release and the notification, another thread could read the old value from a different subscriber callback.
144
+ - Recommendation: This is acceptable for eventual consistency but should be documented as such.
145
+
146
+ 4. **Mutex ordering risk** (Impact: Low)
147
+ - Issue: Memory uses `@mutex`, `@subscription_mutex`, and `@waiter_mutex`. The locking order is generally consistent (main > subscription > waiter), but `notify_subscribers_async` acquires `@subscription_mutex` after releasing `@mutex`. If a subscriber callback re-enters Memory (calls `set` or `get`), this could deadlock.
148
+ - Recommendation: Document the locking contract. Consider using a single mutex or ensure subscribers always dispatch asynchronously (which they do via `dispatch_async`, mitigating this in practice).
149
+
150
+ #### Recommendations
151
+ 1. **Promote processing guard from example to core** (Priority: High, Effort: Small)
152
+ 2. **Replace bare Thread.new with a pool** (Priority: Medium, Effort: Small)
153
+ 3. **Document concurrency contract for Memory** (Priority: Medium, Effort: Small)
154
+
155
+ ---
156
+
157
+ ### API Design Lead - Developer Experience Architect
158
+
159
+ **Perspective**: Evaluates public API surface, developer experience, and Ruby idiomaticness
160
+
161
+ #### Key Observations
162
+ - Builder/factory pattern (`RobotLab.build`) is clean and discoverable
163
+ - `with_*` chaining on Robot delegates to chat and returns `self` -- idiomatic Ruby
164
+ - Template system with YAML front matter is elegant for prompt engineering workflows
165
+ - `on_message` block arity detection (1 arg = auto-ack, 2 args = manual) is clever and well-documented
166
+
167
+ #### Strengths
168
+ 1. **Progressive disclosure**: Simple use (`RobotLab.build.run("Hello")`) to complex (`Robot.new` with 20+ params)
169
+ 2. **Consistent to_h/to_json**: Every domain object serializes cleanly
170
+ 3. **Smart defaults**: `name: "robot"`, `enable_cache: true`, `mcp: :none`
171
+ 4. **RobotMessage as Data.define**: Immutable value object with composite `key` -- excellent
172
+
173
+ #### Concerns
174
+ 1. **Constructor parameter overload** (Impact: Medium)
175
+ - Issue: `Robot#initialize` takes 20 keyword parameters. While each has a sensible default, the signature is intimidating and hard to scan. Some parameters are only relevant in specific contexts (e.g., `mcp_servers` is legacy, `bus` only for multi-robot).
176
+ - Recommendation: Consider a builder pattern or configuration object for advanced parameters. The `with_*` chaining pattern already exists -- lean into it: `RobotLab.build(name: "bot").with_bus(bus).with_template(:helper)`.
177
+
178
+ 2. **Dual system prompt path** (Impact: Low)
179
+ - Issue: `system_prompt:` in constructor AND template body both set instructions via `@chat.with_instructions`. If both are provided, the system prompt is appended after the template -- but this isn't documented.
180
+ - Recommendation: Document the interaction explicitly: "template body renders first, then system_prompt is appended."
181
+
182
+ 3. **`run` method overloading** (Impact: Medium)
183
+ - Issue: `Robot#run` accepts a `message`, plus `network:`, `network_memory:`, `memory:`, `mcp:`, `tools:`, and `**kwargs`. The `kwargs` serve double duty: they're passed to template re-rendering AND to `ask()` (via `kwargs.slice(:with)`). This coupling is confusing.
184
+ - Recommendation: Split template context from ask options more explicitly, e.g., `run(message, context: {}, with: [])`.
185
+
186
+ 4. **`send_message` vs `send_reply` naming** (Impact: Low)
187
+ - Issue: `send_message` creates a new message; `send_reply` creates a reply. Both return `RobotMessage`. The naming is clear, but neither is "send" in the IO sense -- they publish to a bus channel. `publish_message` / `publish_reply` would be more accurate.
188
+ - Recommendation: Keep current names for API stability but document that "send" means "publish to bus channel."
189
+
190
+ #### Recommendations
191
+ 1. **Document template + system_prompt interaction** (Priority: Medium, Effort: Small)
192
+ 2. **Consider builder pattern for Robot construction** (Priority: Low, Effort: Medium)
193
+ 3. **Clarify kwargs routing in Robot#run** (Priority: Medium, Effort: Small)
194
+
195
+ ---
196
+
197
+ ### Reliability Engineer - Error Handling & Resilience Specialist
198
+
199
+ **Perspective**: Assesses error handling, failure modes, and system resilience
200
+
201
+ #### Key Observations
202
+ - Error hierarchy is clean: `Error < StandardError` with 5 specific subclasses
203
+ - `Errors` module provides serialization/deserialization and `capture` wrapper
204
+ - MCP connection failures are logged-and-continued, not raised -- good for optional integrations
205
+
206
+ #### Strengths
207
+ 1. **Graceful MCP degradation**: `MCP::Client#connect` catches exceptions and sets `@connected = false`, allowing the robot to function without MCP tools
208
+ 2. **Error hierarchy covers all domains**: Config, Tool, Inference, MCP, Bus
209
+ 3. **Waiter timeout produces clear exception**: `AwaitTimeout` with message including key name and timeout value
210
+ 4. **Errors.capture utility**: Clean pattern for wrapping blocks in `{ data: result }` / `{ error: serialized }` envelopes
211
+
212
+ #### Concerns
213
+ 1. **Silent thread errors in dispatch_async** (Impact: High)
214
+ - Issue: `Utils#dispatch_async` wraps Thread failures in `warn "RobotLab async dispatch error: #{e.message}"` but the error is otherwise swallowed. Memory subscription callbacks that fail will silently drop. The same is true for Async tasks which swallow exceptions.
215
+ - Recommendation: Add an error callback (`on_async_error`) to Memory or provide a global error handler via config.
216
+
217
+ 2. **No retry logic for LLM calls** (Impact: Medium)
218
+ - Issue: `Robot#run` delegates to `RubyLLM::Agent#ask` with no retry wrapper. LLM APIs frequently return 429 (rate limit) or 503 (overloaded). While RubyLLM may have internal retry logic (configurable via `max_retries`), RobotLab doesn't add its own layer for network-level retries or circuit breaking.
219
+ - Recommendation: This is acceptable if RubyLLM handles retries internally (which it does via `max_retries` in config). Document that retry behavior is delegated to RubyLLM's configuration.
220
+
221
+ 3. **MCP Client reconnection** (Impact: Medium)
222
+ - Issue: If an MCP server goes down mid-conversation, `call_tool` raises `MCPError` ("Not connected"). There's no automatic reconnection attempt.
223
+ - Recommendation: Add a `reconnect` method or auto-reconnect on `MCPError` in `call_tool`. For v0.0.5 this is acceptable -- flag for v0.1.0.
224
+
225
+ 4. **Memory.set with nil value** (Impact: Low)
226
+ - Issue: Setting a key to `nil` via `memory.set(:key, nil)` stores nil. But `get_single` treats nil as "not yet available" and enters the wait path. This means you can't intentionally store nil and have waiters receive it.
227
+ - Recommendation: Use a sentinel value or `key?` check instead of `value.nil?` in the wait path.
228
+
229
+ #### Recommendations
230
+ 1. **Add configurable async error handler** (Priority: High, Effort: Small)
231
+ 2. **Document retry delegation to RubyLLM** (Priority: Medium, Effort: Small)
232
+ 3. **Fix nil-value handling in Memory wait path** (Priority: Medium, Effort: Small)
233
+ 4. **Add MCP auto-reconnect** (Priority: Low, Effort: Medium)
234
+
235
+ ---
236
+
237
+ ### Testing Strategist - Quality Assurance Architect
238
+
239
+ **Perspective**: Reviews test architecture, coverage gaps, and testing patterns
240
+
241
+ #### Key Observations
242
+ - Test:source ratio is >1:1 (5,425 test lines vs 5,050 source lines)
243
+ - Test helper provides `build_robot`, `build_network`, `build_tool` factories
244
+ - `wait_until` helper for async testing with monotonic clock
245
+ - Tests use real RubyLLM with dummy API key -- unit tests don't make real API calls
246
+
247
+ #### Strengths
248
+ 1. **Good test file correspondence**: Every source file in `lib/robot_lab/` has a matching `_test.rb`
249
+ 2. **MCP transport tests**: All four transports (stdio, websocket, SSE, HTTP) have dedicated test files
250
+ 3. **SimpleCov with groups**: Coverage is organized by component area
251
+ 4. **No VCR/WebMock dependency in test_helper**: Tests are written to be unit-testable without network mocking
252
+
253
+ #### Concerns
254
+ 1. **No integration tests visible** (Impact: Medium)
255
+ - Issue: The Rakefile mentions `integration` task but no integration test directory or files are visible. The bus messaging, network pipeline execution, and MCP tool calling would benefit from integration tests.
256
+ - Recommendation: Add integration tests for key workflows: Robot -> Network -> Memory flow, Bus messaging round-trip, MCP tool discovery -> execution.
257
+
258
+ 2. **Streaming module untested** (Impact: Medium)
259
+ - Issue: There is a `streaming_test.rb` but the streaming subsystem is not integrated into execution. Unclear what the test covers since streaming is not wired in.
260
+ - Recommendation: Either test the streaming API contract in isolation or defer until integration.
261
+
262
+ 3. **No test for concurrent Memory access** (Impact: Medium)
263
+ - Issue: Memory's reactive features (subscribe, wait, pattern matching) involve concurrency. Tests should verify thread-safety of subscribe + set, multiple waiters on same key, and timeout behavior.
264
+ - Recommendation: Add multi-threaded Memory stress tests.
265
+
266
+ 4. **Robot test may require network** (Impact: Low)
267
+ - Issue: `robot_test.rb` creates real Robot instances which call `RubyLLM::Agent#initialize` and set up a persistent chat. If RubyLLM's agent init makes network calls (model validation, etc.), tests could be flaky.
268
+ - Recommendation: Verify that Robot construction is fully offline with the test API key. If not, stub RubyLLM initialization.
269
+
270
+ #### Recommendations
271
+ 1. **Add integration test suite** (Priority: High, Effort: Medium)
272
+ 2. **Add concurrent Memory tests** (Priority: Medium, Effort: Small)
273
+ 3. **Verify Robot construction is offline-safe** (Priority: Medium, Effort: Small)
274
+
275
+ ---
276
+
277
+ ### Pragmatic Enforcer - YAGNI & Simplicity Advocate
278
+
279
+ **Perspective**: Challenges unnecessary complexity and advocates for simplest viable solutions
280
+
281
+ #### Key Observations
282
+ - At v0.0.5, the framework has an appropriate scope for what it does
283
+ - Some infrastructure is built ahead of need (streaming, Redis backend, adapters references)
284
+ - The core Robot -> Network -> Memory flow is solid and well-tested
285
+
286
+ #### Pragmatic Analysis
287
+
288
+ | Feature | Necessity (0-10) | Complexity (0-10) | Ratio | Recommendation |
289
+ |---------|-----------------|-------------------|-------|----------------|
290
+ | Robot core | 10 | 4 | 0.4 | **Implement** |
291
+ | Network/Pipeline | 9 | 5 | 0.6 | **Implement** |
292
+ | Memory (reactive) | 8 | 6 | 0.8 | **Implement** |
293
+ | Bus messaging | 7 | 5 | 0.7 | **Implement** |
294
+ | MCP integration | 7 | 6 | 0.9 | **Implement** |
295
+ | Tool hierarchy | 6 | 3 | 0.5 | **Implement** |
296
+ | Streaming events | 4 | 4 | 1.0 | **Defer** -- not wired in |
297
+ | Redis backend | 3 | 3 | 1.0 | **Defer** -- no users yet |
298
+ | ToolManifest | 3 | 2 | 0.7 | **Simplify** -- used? |
299
+ | Adapters (absent) | 2 | 0 | 0.0 | **Remove references** |
300
+ | UserMessage | 4 | 2 | 0.5 | **Keep** -- small cost |
301
+
302
+ #### Concerns
303
+ 1. **Streaming infrastructure without consumers** (Pragmatic Score: 1.0)
304
+ - Issue: 95 lines of code (Events + Context + SequenceCounter) defining 22 event types that nothing publishes. This is pure speculative infrastructure.
305
+ - Recommendation: Remove or move to a branch. Reintroduce when streaming is actually needed. Cost of waiting: near zero (the design is clean and can be re-created quickly).
306
+
307
+ 2. **RedisBackend built but unused** (Pragmatic Score: 1.0)
308
+ - Issue: RedisBackend is 50 lines that implement a key-value interface on Redis. But no tests exercise it, no examples use it, and the auto-detection path silently falls back to Hash. It's dead weight that creates maintenance burden.
309
+ - Recommendation: Remove from core. Add as an optional extension gem or bring back when a use case materializes.
310
+
311
+ 3. **ToolManifest may be over-built** (Pragmatic Score: 0.7)
312
+ - Issue: ToolManifest provides Enumerable, merge, replace, fetch-with-error, has?, count, length, clear, from_hash -- a full collection API. But it's unclear if anything uses it in the execution path (Robot uses `@local_tools + @mcp_tools` arrays directly).
313
+ - Recommendation: Check if ToolManifest is used. If only for external API, simplify to a thin lookup wrapper.
314
+
315
+ 4. **Message type system is well-sized** (Pragmatic Score: 0.5)
316
+ - The Message/TextMessage/ToolCallMessage/ToolResultMessage hierarchy is exactly as complex as it needs to be. Good balance.
317
+
318
+ #### Recommendations
319
+ 1. **Remove or defer streaming module** (Priority: Medium, Effort: Small)
320
+ 2. **Remove RedisBackend** (Priority: Low, Effort: Small)
321
+ 3. **Audit ToolManifest usage** (Priority: Low, Effort: Small)
322
+
323
+ ---
324
+
325
+ ## Collaborative Discussion
326
+
327
+ ### Consensus Points
328
+
329
+ All reviewers agree on:
330
+ 1. **Core architecture is sound**: Robot, Network, Memory separation of concerns is clean and appropriate
331
+ 2. **Async re-entrancy is the highest-risk issue**: The documented-but-not-implemented processing guard needs to be in core, not just examples
332
+ 3. **Test coverage is strong by ratio** but lacks integration and concurrency testing
333
+ 4. **Streaming infrastructure is premature**: Should be deferred or removed
334
+
335
+ ### Points of Debate
336
+
337
+ - **Systems Architect** wants eager_load removed; **Reliability Engineer** notes it prevents autoloading race conditions in multi-threaded environments. **Consensus**: Make it conditional on Rails.
338
+ - **API Design Lead** suggests builder pattern for Robot; **Pragmatic Enforcer** counters that the existing `with_*` chaining is already a builder pattern and adding another layer would be over-engineering. **Consensus**: Document `with_*` chaining as the recommended construction pattern.
339
+ - **Concurrency Specialist** wants a thread pool; **Pragmatic Enforcer** notes this adds a concurrent-ruby dependency. **Consensus**: Require Async for reactive features (it's already a dependency), removing the Thread.new fallback.
340
+
341
+ ---
342
+
343
+ ## Consolidated Findings
344
+
345
+ ### Strengths
346
+ 1. **Clean module decomposition**: Each class has one responsibility; concerns are extracted into modules
347
+ 2. **Excellent serialization**: Every domain object implements `to_h`, `to_json`, `from_hash` consistently
348
+ 3. **Progressive complexity**: Simple `build.run` for basic use; full Network+Memory+Bus for complex orchestration
349
+ 4. **Test discipline**: >1:1 test-to-source ratio with per-class test coverage
350
+ 5. **Configuration elegance**: 4-level hierarchical resolution with `:inherit`/`:none` semantics
351
+
352
+ ### Areas for Improvement
353
+ 1. **Async safety**: Processing guard in Robot, thread pool in Utils, nil-value handling in Memory
354
+ 2. **Dead code**: Streaming module, RedisBackend, adapters references, possible NetworkRun ghosts
355
+ 3. **Documentation drift**: CLAUDE.md references classes/patterns that don't match current code
356
+ 4. **Integration testing**: No end-to-end tests for Robot-Network-Memory-Bus workflow
357
+
358
+ ### Technical Debt
359
+
360
+ **High Priority**:
361
+ - Async re-entrancy in Robot#run: Can corrupt LLM API message ordering. Resolution: Add processing guard. Effort: Small.
362
+
363
+ **Medium Priority**:
364
+ - Streaming module is orphaned: Adds 95 lines of unmaintained infrastructure. Resolution: Remove or integrate. Effort: Small-Medium.
365
+ - Thread leak in dispatch_async: Can create unbounded threads. Resolution: Use Async everywhere. Effort: Small.
366
+ - Memory nil-value ambiguity: Can't distinguish "not set" from "set to nil". Resolution: Use sentinel. Effort: Small.
367
+
368
+ **Low Priority**:
369
+ - RedisBackend untested and unused: 50 lines of dead weight. Resolution: Remove. Effort: Small.
370
+ - ToolManifest possibly unused: Full collection API that may not be called. Resolution: Audit. Effort: Small.
371
+
372
+ ### Risks
373
+
374
+ **Technical Risks**:
375
+ - **LLM API ordering corruption**: Likelihood: Medium (requires async + bus), Impact: High, Mitigation: Processing guard
376
+ - **Thread exhaustion**: Likelihood: Low (requires many subscriptions), Impact: Medium, Mitigation: Thread pool or Async-only
377
+ - **RubyLLM breaking changes**: Likelihood: Medium (< 1.0 dependency), Impact: High, Mitigation: Pin version more tightly
378
+
379
+ ---
380
+
381
+ ## Recommendations
382
+
383
+ ### Immediate (0-2 weeks)
384
+ 1. **Add processing guard to Robot#run**: Promote the `@processing` + `@queue` pattern from `examples/14_rusty_circuit/scout.rb` into `Robot` or `BusMessaging`. This prevents the async re-entrancy bug that corrupts Anthropic API message ordering.
385
+ - Success Criteria: Bus message delivery during an active `run()` queues instead of interleaving
386
+ 2. **Clean up ghost references**: Remove `NetworkRun` references from Robot#run params and MCPManagement. Update CLAUDE.md to match current code.
387
+ - Success Criteria: No references to classes that don't exist
388
+ 3. **Fix Memory nil-value handling**: Use `@backend.key?(key)` instead of `value.nil?` in `get_single` wait path.
389
+ - Success Criteria: `memory.set(:key, nil)` wakes waiters
390
+
391
+ ### Short-term (2-8 weeks)
392
+ 1. **Remove or gate streaming module**: Move `Streaming::Events`, `Streaming::Context`, and `Streaming::SequenceCounter` behind a feature flag or remove entirely until streaming is integrated.
393
+ - Success Criteria: No orphaned infrastructure code
394
+ 2. **Replace Thread.new fallback in dispatch_async**: Require callers to be inside Async for reactive features, or use a bounded thread pool.
395
+ - Success Criteria: No unbounded thread creation
396
+ 3. **Add integration tests**: Test Robot-Network-Memory pipeline, Bus messaging round-trip, and concurrent Memory access.
397
+ - Success Criteria: CI runs integration suite without hanging
398
+ 4. **Add configurable error handler**: `RobotLab.configure { |c| c.on_async_error = ->(e) { ... } }` for async dispatch errors.
399
+ - Success Criteria: Errors in subscription callbacks are reportable
400
+
401
+ ### Long-term (2-6 months)
402
+ 1. **Integrate streaming into execution**: Wire `Streaming::Context` into `Robot#run` and `Network#run` to emit lifecycle and delta events. This enables real-time UIs and debugging tools.
403
+ - Success Criteria: `robot.run("Hello") { |event| ... }` yields streaming events
404
+ 2. **Add MCP auto-reconnect**: Implement connection health checks and automatic reconnection in MCP::Client.
405
+ - Success Criteria: Transient MCP server restarts don't break long-running robot sessions
406
+ 3. **Formalize Network execution model**: Document whether Network runs robots sequentially, in parallel, or via the dependency graph in SimpleFlow. Clarify `call_parallel` vs `call` semantics.
407
+ - Success Criteria: Users can predict execution order from Network definition
408
+
409
+ ---
410
+
411
+ ## Success Metrics
412
+ 1. **Zero async re-entrancy bugs**: Current: documented but unprotected -> Target: guard in core (2 weeks)
413
+ 2. **Dead code ratio**: Current: ~145 lines of orphaned streaming/Redis -> Target: 0 lines (4 weeks)
414
+ 3. **Integration test count**: Current: 0 -> Target: 5+ workflows covered (6 weeks)
415
+ 4. **Doc accuracy**: Current: CLAUDE.md references missing classes -> Target: 100% accurate (2 weeks)
416
+
417
+ ---
418
+
419
+ ## Follow-up
420
+ **Next Review**: After v0.1.0 release or 3 months, whichever comes first
421
+ **Tracking**: Create issues for Immediate and Short-term recommendations
422
+
423
+ ## Related Documentation
424
+ - `CLAUDE.md`: Project instructions (needs update for removed classes)
425
+ - `MEMORY.md`: Documents async re-entrancy bug and workarounds
426
+ - `examples/14_rusty_circuit/`: Reference implementation for processing guard pattern
427
+ - `examples/15_memory_network_and_bus/`: Reference for network + bus workflow
@@ -0,0 +1,57 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(find:*)",
5
+ "Bash(ls:*)",
6
+ "WebSearch",
7
+ "WebFetch(domain:rubyllm.com)",
8
+ "Bash(bundle exec ruby:*)",
9
+ "Bash(./02_tools.rb)",
10
+ "WebFetch(domain:builders.ramp.com)",
11
+ "mcp__playwright-mcp__playwright_navigate",
12
+ "mcp__playwright-mcp__playwright_get_visible_text",
13
+ "mcp__playwright-mcp__playwright_get_visible_html",
14
+ "mcp__playwright-mcp__playwright_evaluate",
15
+ "Bash(curl:*)",
16
+ "mcp__playwright-mcp__playwright_close",
17
+ "mcp__plugin_compound-engineering_context7__resolve-library-id",
18
+ "WebFetch(domain:github.com)",
19
+ "Bash(tree:*)",
20
+ "mcp__plugin_compound-engineering_context7__query-docs",
21
+ "Bash(ruby -c:*)",
22
+ "Bash(ruby -e:*)",
23
+ "Bash(ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY ruby:*)",
24
+ "Bash(ruby:*)",
25
+ "Bash(cat:*)",
26
+ "Bash(bundle exec rake test:*)",
27
+ "Bash(xargs cat:*)",
28
+ "Bash(wc:*)",
29
+ "Bash(bundle exec gem:*)",
30
+ "Bash(bundle install:*)",
31
+ "Bash(open coverage/index.html)",
32
+ "mcp__crimson__analyze_ruby",
33
+ "Bash(mkdocs build:*)",
34
+ "Bash(gem specification:*)",
35
+ "WebFetch(domain:rubygems.org)",
36
+ "WebFetch(domain:madbomber.github.io)",
37
+ "WebFetch(domain:raw.githubusercontent.com)",
38
+ "Bash(bundle show:*)",
39
+ "Bash(for f in examples/*.rb)",
40
+ "Bash(do echo \"Checking syntax: $f\")",
41
+ "Bash(done)",
42
+ "Bash(bundle exec rake:*)",
43
+ "Bash(chmod:*)",
44
+ "Bash(bundle lock:*)",
45
+ "Bash(gem list:*)",
46
+ "Bash(gem search:*)",
47
+ "Bash(gem contents:*)",
48
+ "Bash(ROBOT_LAB_DEFAULT_MODEL=gpt-4-test bundle exec ruby:*)",
49
+ "mcp__github__issue_read",
50
+ "mcp__plugin_claude-memory_memory__memory_recall",
51
+ "mcp__github__list_issues",
52
+ "mcp__github__add_issue_comment",
53
+ "WebFetch(domain:paolino.me)",
54
+ "Bash(bin/rails runner *)"
55
+ ]
56
+ }
57
+ }
@@ -0,0 +1,2 @@
1
+ [mcp_servers.crimson]
2
+ command = "crimson"
data/.irbrc CHANGED
@@ -1,6 +1,6 @@
1
1
  begin
2
2
  load File.expand_path('lib/robot_lab.rb', __dir__)
3
3
  rescue LoadError => e
4
- $stderr.puts "[robot_lab] #{e.message}"
5
- $stderr.puts "[robot_lab] Run `bundle exec irb` to load RobotLab"
4
+ warn "[robot_lab] #{e.message}"
5
+ warn "[robot_lab] Run `bundle exec irb` to load RobotLab"
6
6
  end
data/.rubocop.yml ADDED
@@ -0,0 +1,172 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 4.0
5
+ Exclude:
6
+ - 'examples/**/*'
7
+ - 'vendor/**/*'
8
+ - 'dead_code/**/*'
9
+ - '_notes/**/*'
10
+
11
+ # ── Style: disabled cops ───────────────────────────────────────────────────
12
+ Style/StringLiterals:
13
+ Enabled: false
14
+
15
+ Style/StringLiteralsInInterpolation:
16
+ Enabled: false
17
+
18
+ Style/Documentation:
19
+ Enabled: false
20
+
21
+ # Ruby 4.0 freezes string literals by default
22
+ Style/FrozenStringLiteralComment:
23
+ Enabled: false
24
+
25
+ Style/IfUnlessModifier:
26
+ Enabled: false
27
+
28
+ Style/RescueModifier:
29
+ Enabled: false
30
+
31
+ Style/TrivialAccessors:
32
+ Enabled: false
33
+
34
+ Style/MultilineTernaryOperator:
35
+ Enabled: false
36
+
37
+ Style/SafeNavigation:
38
+ Enabled: false
39
+
40
+ Style/EmptyClassDefinition:
41
+ Enabled: false
42
+
43
+ Style/ClassAndModuleChildren:
44
+ Enabled: false
45
+
46
+ Style/RescueStandardError:
47
+ Enabled: false
48
+
49
+ Style/OneClassPerFile:
50
+ Enabled: false
51
+
52
+ # Both % and format/sprintf are acceptable
53
+ Style/FormatString:
54
+ Enabled: false
55
+
56
+ # String concatenation and interpolation are both acceptable
57
+ Style/StringConcatenation:
58
+ Enabled: false
59
+
60
+ # ── Layout ─────────────────────────────────────────────────────────────────
61
+ Layout/LineLength:
62
+ Max: 140
63
+
64
+ Layout/ExtraSpacing:
65
+ Enabled: false
66
+
67
+ Layout/HashAlignment:
68
+ Enabled: false
69
+
70
+ Layout/FirstHashElementIndentation:
71
+ Enabled: false
72
+
73
+ Layout/EmptyLineAfterGuardClause:
74
+ Enabled: false
75
+
76
+ # ── Naming ─────────────────────────────────────────────────────────────────
77
+ # Single-char params (c, e, n) are acceptable throughout
78
+ Naming/MethodParameterName:
79
+ Enabled: false
80
+
81
+ Naming/VariableNumber:
82
+ Exclude:
83
+ - 'test/**/*'
84
+
85
+ Naming/RescuedExceptionsVariableName:
86
+ Enabled: false
87
+
88
+ # set_results and similar explicit setters are clear and conventional
89
+ Naming/AccessorMethodName:
90
+ Enabled: false
91
+
92
+ # has_tool_calls? and similar are clear and conventional
93
+ Naming/PredicatePrefix:
94
+ Enabled: false
95
+
96
+ # Test helper methods don't need to follow predicate naming rules
97
+ Naming/PredicateMethod:
98
+ Exclude:
99
+ - 'test/**/*'
100
+
101
+ # ── Lint: relax noisy cops on intentional patterns ─────────────────────────
102
+ Lint/EmptyBlock:
103
+ Exclude:
104
+ - 'test/**/*'
105
+
106
+ # Library and framework methods commonly accept args for API/documentation purposes
107
+ Lint/UnusedMethodArgument:
108
+ Enabled: false
109
+
110
+ Lint/ConstantDefinitionInBlock:
111
+ Exclude:
112
+ - 'Rakefile'
113
+ - 'test/**/*'
114
+
115
+ # ── Gemspec ────────────────────────────────────────────────────────────────
116
+ Gemspec/DevelopmentDependencies:
117
+ EnforcedStyle: Gemfile
118
+
119
+ Gemspec/RequiredRubyVersion:
120
+ Enabled: false
121
+
122
+ Gemspec/OrderedDependencies:
123
+ Enabled: false
124
+
125
+ # ── Metrics ────────────────────────────────────────────────────────────────
126
+ # Framework-level code (routers, parsers, orchestrators) is inherently complex.
127
+ # Flog is the primary complexity gate — these RuboCop thresholds catch only
128
+ # egregious outliers without false-positiving every dispatch method.
129
+
130
+ Metrics/MethodLength:
131
+ Max: 35
132
+ CountAsOne:
133
+ - heredoc
134
+ - array
135
+ - hash
136
+ Exclude:
137
+ - 'test/**/*'
138
+
139
+ Metrics/AbcSize:
140
+ Max: 40
141
+ Exclude:
142
+ - 'test/**/*'
143
+
144
+ Metrics/ClassLength:
145
+ Max: 600
146
+ Exclude:
147
+ - 'test/**/*'
148
+
149
+ Metrics/ModuleLength:
150
+ Max: 200
151
+ Exclude:
152
+ - 'test/**/*'
153
+
154
+ Metrics/CyclomaticComplexity:
155
+ Max: 20
156
+ Exclude:
157
+ - 'test/**/*'
158
+
159
+ Metrics/PerceivedComplexity:
160
+ Max: 20
161
+ Exclude:
162
+ - 'test/**/*'
163
+
164
+ # Long method signatures with keyword args are a Ruby framework idiom
165
+ Metrics/ParameterLists:
166
+ Enabled: false
167
+
168
+ Metrics/BlockLength:
169
+ Exclude:
170
+ - 'Rakefile'
171
+ - '*.gemspec'
172
+ - 'test/**/*'