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,192 @@
1
+ # Review: `agent2agent` Ruby Gem
2
+
3
+ **Source:** https://github.com/general-intelligence-systems/agent2agent
4
+ **Docs:** https://general-intelligence-systems.github.io/agent2agent/
5
+ **License:** Apache 2.0
6
+ **Ruby:** >= 3.2
7
+ **Reviewed:** 2026-05-05
8
+
9
+ ---
10
+
11
+ ## What It Is
12
+
13
+ A complete Ruby implementation of Google's A2A (Agent-to-Agent) protocol — an open standard for interoperable, cross-vendor AI agent communication over HTTP. The gem provides both a server (Rack app) and a client, plus SSE streaming, task persistence, and push notifications.
14
+
15
+ ---
16
+
17
+ ## Wire Protocol
18
+
19
+ Two parallel transport bindings, both implemented:
20
+
21
+ | Transport | Path | Format |
22
+ |---|---|---|
23
+ | JSON-RPC 2.0 | `POST /a2a` | `{"jsonrpc":"2.0","method":"SendMessage","params":{...}}` |
24
+ | HTTP+JSON/REST | `POST /message:send`, `GET /tasks/{id}`, etc. | Plain JSON |
25
+ | Agent Discovery | `GET /.well-known/agent-card.json` | Capabilities manifest |
26
+
27
+ ### The 11 Protocol Operations
28
+
29
+ 1. `SendMessage` — POST `/message:send` (synchronous)
30
+ 2. `SendStreamingMessage` — POST `/message:stream` (SSE, server-streaming)
31
+ 3. `GetTask` — GET `/tasks/{id}`
32
+ 4. `ListTasks` — GET `/tasks`
33
+ 5. `CancelTask` — POST `/tasks/{id}:cancel`
34
+ 6. `SubscribeToTask` — SSE stream of task updates
35
+ 7. `CreateTaskPushNotificationConfig` — POST `/tasks/{id}/push`
36
+ 8. `GetTaskPushNotificationConfig` — GET `/tasks/{id}/push/{config_id}`
37
+ 9. `ListTaskPushNotificationConfigs` — GET `/tasks/{id}/push`
38
+ 10. `DeleteTaskPushNotificationConfig` — DELETE `/tasks/{id}/push/{config_id}`
39
+ 11. `GetExtendedAgentCard` — GET extended agent card
40
+
41
+ ### Task State Machine
42
+
43
+ `SUBMITTED → WORKING → INPUT_REQUIRED → COMPLETED / FAILED / CANCELED / REJECTED`
44
+
45
+ ---
46
+
47
+ ## Key Classes and Their Roles
48
+
49
+ | Class | Role |
50
+ |---|---|
51
+ | `A2A::Agent` | DSL: `on("SendMessage") { \|req\| respond(...) }` — registers operation handlers |
52
+ | `A2A::Server` | Rack app — mountable in any Rack stack or Rails router |
53
+ | `A2A::Client` | Async-HTTP client; all 11 ops auto-generated as snake_case methods |
54
+ | `A2A::Proto` | Parses the real `data/a2a.proto` file — single source of truth for operations |
55
+ | `A2A::Schema` | Loads 47-type `data/a2a.json`; validates with `json_schemer`; camelCase/snake_case |
56
+ | `A2A::TaskStore` | In-memory task CRUD with `Thread::Queue` pub/sub and webhook delivery |
57
+ | `A2A::Store::SQLite` | Production drop-in: WAL mode, indexed, fiber-safe `Async::Queue` pub/sub |
58
+ | `A2A::SSE::Stream` | Subclasses `Protocol::HTTP::Body::Writable`; Falcon passes it untouched |
59
+ | `A2A::Bindings::JsonRpc` | Rack middleware that parses JSON-RPC envelopes and wraps responses |
60
+
61
+ ### Agent DSL Example
62
+
63
+ ```ruby
64
+ agent = A2A::Agent.new do
65
+ on "SendMessage", "SendStreamingMessage" do |context|
66
+ task = context.store.create(context.request)
67
+ stream = context.stream
68
+
69
+ Async do
70
+ result = robot.run(context.request.params[:message])
71
+ context.store.complete(task.id, result)
72
+ stream.event(result, type: "result")
73
+ stream.finish
74
+ end
75
+
76
+ context.respond(task)
77
+ end
78
+ end
79
+
80
+ server = A2A::Server.new
81
+ server.register(agent)
82
+ run server
83
+ ```
84
+
85
+ ### Client Example
86
+
87
+ ```ruby
88
+ Async do
89
+ client = A2A::Client.new("http://localhost:9292")
90
+ card = client.agent_card
91
+ result = client.send_message(message: { role: "user", parts: [{ text: "Hello" }] })
92
+ puts result
93
+ end
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Notable Patterns
99
+
100
+ - **Duck-typed stores:** Any object implementing the task store interface can be swapped in — `TaskStore` (in-memory) or `Store::SQLite` (production), or a custom implementation.
101
+ - **Proto as source of truth:** `Proto` parses `data/a2a.proto` directly to extract operation metadata — stays in sync with the Google A2A spec automatically.
102
+ - **Fiber-native:** The SQLite store's pub/sub uses `Async::Queue`; SSE bodies use `Protocol::HTTP::Body::Writable`. Fully fiber-safe when run under Falcon.
103
+ - **`returnImmediately` flag:** Background jobs return a task ID immediately; updates stream via SSE as work proceeds.
104
+ - **`STATE_INPUT_REQUIRED`:** Multi-turn conversations — agent transitions to this state when it needs more user input before continuing. Client sends another `SendMessage` referencing the same task context.
105
+ - **Inline tests via `scampi`:** Tests live inside source files (`test do ... end`), not a separate test directory.
106
+ - **Tenant-prefixed paths:** Every REST route has a variant: `/{tenant}/message:send` for multi-tenant deployments.
107
+
108
+ ---
109
+
110
+ ## Authentication
111
+
112
+ - **AgentCard** declares supported auth schemes in the capabilities manifest
113
+ - **Push notification configs** carry per-webhook auth: `scheme` + `credentials` sent as `Authorization: Bearer <credentials>` on webhook delivery; optionally also `X-A2A-Notification-Token`
114
+ - Incoming request authentication is left to the application layer (standard Rack middleware pattern)
115
+
116
+ ---
117
+
118
+ ## Dependencies
119
+
120
+ **Runtime:**
121
+ - `async (~> 2.0)`, `async-http (~> 0.95)` — fiber concurrency and HTTP
122
+ - `rack (~> 3.0)` — server composition (pure Rack, Rails-mountable)
123
+ - `json_schemer (~> 2.5)` — schema validation against 47 A2A types
124
+ - `google-protobuf (~> 4.34)` — proto file parsing
125
+ - `sqlite3` — persistent task store
126
+ - `protocol-http (~> 0.62)` — `Body::Writable` for SSE
127
+ - `scampi` — inline test framework
128
+ - `console` — structured logging
129
+
130
+ **Development:**
131
+ - `falcon (~> 0.55)` — async HTTP server for running agents
132
+
133
+ ---
134
+
135
+ ## Applicability to Your Projects
136
+
137
+ ### RobotLab — High Value
138
+
139
+ The most compelling integration: expose each `Robot` or `Network` as a standard A2A service. This enables cross-language orchestration (Python LangChain, JS Genkit, Go agents, Google Cloud agents) without any shared code.
140
+
141
+ **Robot-as-A2A-Service:**
142
+ - `A2A::Agent` adapter delegates `SendMessage` → `robot.run(request.message)`, result becomes the A2A task result
143
+ - Publish an AgentCard at `/.well-known/agent-card.json` advertising each robot's capabilities and tools
144
+ - Use `A2A::Store::SQLite` to persist tasks across requests (stateless HTTP tier in front of stateful robots)
145
+
146
+ **Streaming:**
147
+ - `SendStreamingMessage` + `SSE::Stream` maps directly onto RubyLLM's streaming callbacks
148
+ - Streaming events become real-time SSE — no additional infrastructure needed
149
+
150
+ **Cross-process robot networks:**
151
+ - Instead of `TypedBus` (in-process pub/sub only), robots in separate processes or machines call each other via `A2A::Client`
152
+ - A Network router can delegate to remote robots via `client.send_message(...)` — standard HTTP replaces shared-memory message passing
153
+
154
+ **Background jobs:**
155
+ - A2A's push notification config CRUD gives external systems a standard webhook protocol for task completion
156
+ - Maps cleanly onto RobotLab's existing async robot semantics
157
+
158
+ **Multi-turn conversations:**
159
+ - `STATE_INPUT_REQUIRED` maps directly to RobotLab's `AskUser` tool pattern — robot needs user input before continuing
160
+ - Web clients get a proper protocol for handling confirmation flows rather than a terminal prompt
161
+
162
+ **Compatibility note:** Both RobotLab and `agent2agent` use the `async` gem — they compose cleanly. The main requirement is running under Falcon rather than a plain Ruby process. `TypedBus` (`Async::Queue`) and `A2A::Store::PubSub` (`Async::Queue`) are both fiber-based and compatible.
163
+
164
+ ### AIA — Moderate Value
165
+
166
+ - `A2A::Client` could delegate tasks to remote A2A-compliant agents (specialized coding agents, search agents, etc.) instead of calling LLM APIs directly
167
+ - AIA could optionally expose itself as a local A2A server on `localhost:PORT` so IDE plugins or other tools can send it tasks via standard protocol
168
+ - AgentCard discovery would let AIA auto-configure available capabilities when connecting to remote agents
169
+
170
+ ### Rails Apps Generally
171
+
172
+ `A2A::Server` is pure Rack:
173
+
174
+ ```ruby
175
+ # config/routes.rb
176
+ mount A2A::Server.new(agent: my_agent), at: "/agents/myagent"
177
+ ```
178
+
179
+ This works as-is. The 47-type schema validation via `json_schemer` is also useful standalone for validating A2A protocol payloads.
180
+
181
+ ---
182
+
183
+ ## Bottom Line
184
+
185
+ Production-quality gem for its scope. Clean architecture: Rack middleware chain, duck-typed stores, fiber-safe pub/sub, SSE via `protocol-http`. Inline test coverage is extensive.
186
+
187
+ **Highest-value opportunity for RobotLab:** Robot-as-A2A-Service — exposing robots as standards-compliant HTTP endpoints enables cross-language agent orchestration that the current `TypedBus` approach (in-process only) cannot support. This would position RobotLab robots as first-class participants in the emerging A2A ecosystem alongside Python, JavaScript, and Go agent frameworks.
188
+
189
+ **Specific algorithms/patterns worth porting:**
190
+ 1. `A2A::Store::SQLite` pub/sub pattern (Async::Queue-based) — applicable to RobotLab's Memory system
191
+ 2. AgentCard capability manifest — useful for RobotLab's planned tool/capability discovery
192
+ 3. `STATE_INPUT_REQUIRED` state machine entry — formalizes the `AskUser` pattern with a standard protocol state
@@ -0,0 +1,253 @@
1
+ # `agentf` Gem Analysis
2
+
3
+ **Repository:** https://github.com/nealdeters/agentf
4
+ **Author:** Neal Deters
5
+ **Ruby:** 3.3.0+ | **Runtime deps:** `redis ~> 4.8`, `dotenv ~> 2.8`
6
+
7
+ ---
8
+
9
+ ## What It Is
10
+
11
+ A Ruby multi-agent workflow engine for software development. Orchestrates
12
+ role-specialized agents (Planner, Engineer, QA, Reviewer, Security) that share
13
+ Redis memory — but **never calls an LLM itself**. It runs as an MCP server over
14
+ stdio and lets the IDE's AI (Copilot, OpenCode) do the actual inference.
15
+ It is scaffolding, not an API wrapper.
16
+
17
+ Three surfaces:
18
+ - **CLI** (`agentf <subcommand>`) — memory management, code exploration, metrics, evals
19
+ - **MCP server** (`agentf mcp-server`) — 19 tools over stdio for IDE integrations
20
+ - **Ruby API** — `WorkflowEngine`, `Agents::*`, `RedisMemory` for programmatic use
21
+
22
+ ---
23
+
24
+ ## Architecture
25
+
26
+ | Layer | Files | Role |
27
+ |---|---|---|
28
+ | Entry point | `agentf.rb`, `bin/agentf` | Config singleton + CLI boot |
29
+ | CLI | `cli/router.rb`, `cli/memory.rb`, `cli/code.rb` | Subcommand dispatch |
30
+ | Agents | `agents/base.rb`, role subclasses | Role-based agent classes |
31
+ | Workflow | `workflow_engine.rb` | Orchestrator / sequencer |
32
+ | Memory | `memory.rb`, `memory/confirmation_handler.rb` | Redis-backed storage |
33
+ | Contracts | `workflow_contract.rb`, `agent_execution_contract.rb` | Constraint enforcement |
34
+ | Tools | `tools/`, `tools.rb` | Primitive capabilities |
35
+ | Commands | `commands/registry.rb`, `commands/*.rb` | Named command registry |
36
+ | MCP | `mcp/server.rb`, `mcp/stub.rb` | stdio MCP protocol server |
37
+ | Service | `service/providers.rb` | Provider adapters |
38
+ | Installer | `installer.rb` | Manifest generation and provider setup |
39
+
40
+ ---
41
+
42
+ ## Patterns Worth Stealing
43
+
44
+ ### 1. Agents That Describe Themselves at the Class Level
45
+
46
+ All agent metadata — `description`, `deliverables`, `policy_boundaries`,
47
+ `when_to_use`, `commands` — are class methods, not instance state or external
48
+ YAML. Agents are self-documenting, introspectable at install time, and
49
+ verifiable without instantiating anything. The `Installer` reads these at
50
+ install time to generate markdown manifests.
51
+
52
+ ### 2. Three-Mode Contract Enforcement (advisory / enforcing / off)
53
+
54
+ A contract object wraps agent execution with `before!`/`after!` validation.
55
+ Run workflows in `advisory` mode during development (log violations, don't
56
+ stop), flip to `enforcing` for production. TDD phase discipline (`"red"` vs
57
+ `"green"`) is enforced at the contract layer, not by convention.
58
+
59
+ ### 3. Human-in-the-Loop Memory Writes
60
+
61
+ `ConfirmationHandler` wraps Redis writes so that when confirmation is needed,
62
+ instead of raising it returns `{ confirmation: true, payload: ..., instructions: ... }`.
63
+ The caller re-invokes with `confirmedWrite: "confirmed"`. Works identically
64
+ across CLI, MCP, and programmatic callers.
65
+
66
+ ### 4. Deterministic Local Embeddings With No ML Dependency
67
+
68
+ `EmbeddingProvider` SHA256-hashes tokens, uses the hash to pick a dimension in
69
+ a 64-element float vector, then normalizes it. Zero API calls, zero latency,
70
+ fully reproducible. Crude but sufficient for semantic memory search in a
71
+ dev-tool context.
72
+
73
+ ### 5. Black-Box Shell Script Evals
74
+
75
+ Each eval scenario is three files: `prompt.txt`, `scenario.yml`, and
76
+ `verify.sh`. The shell script asserts postconditions against real Redis state.
77
+ Simple, portable, no mocking — `agentf eval run all` just executes them.
78
+
79
+ ### 6. Graceful Redis Capability Degradation
80
+
81
+ The memory layer detects at runtime whether Redis Stack's JSON/Search/Vector
82
+ modules are present and degrades silently. Full semantic search if available;
83
+ plain key-value otherwise. No config flag needed — baked into `RedisMemory`.
84
+
85
+ ### 7. Ruby Generating Its Own TypeScript Integration
86
+
87
+ The installer generates TypeScript plugin files (`agentf-plugin.ts`,
88
+ `tsconfig.json`, `package.json`) from within Ruby for OpenCode integration.
89
+ A Ruby gem producing its own typed IDE plugin layer is unusual and practical.
90
+
91
+ ### 8. Policies Stored in Code, Not Config
92
+
93
+ `policy_boundaries` returns `{ "always" => [...], "ask_first" => [...], "never" => [...] }`
94
+ directly from Ruby class methods. Changing a policy means changing Ruby, not
95
+ YAML — no config drift.
96
+
97
+ ### 9. Workflow Profiles as Constants
98
+
99
+ Workflow compositions are defined as constants in `WorkflowEngine::PROFILES`
100
+ (e.g., `rails_standard`, `rails_37signals`), mapping task types to ordered
101
+ agent sequences. One canonical source of truth for workflow shapes.
102
+
103
+ ---
104
+
105
+ ## RobotLab Applicability Analysis
106
+
107
+ ### Patterns That Don't Apply
108
+
109
+ **Pattern 7 — Ruby Generating Its Own TypeScript Integration**
110
+ agentf is an IDE tool targeting Copilot/OpenCode. RobotLab is a Ruby library with no IDE integration surface. Not relevant.
111
+
112
+ **Pattern 6 — Graceful Redis Capability Degradation**
113
+ Already handled. `Memory` already degrades `redis → hash` fallback at initialization. `DocumentStore` uses fastembed, not Redis Stack — separate concern covered below.
114
+
115
+ ---
116
+
117
+ ### Patterns Worth Implementing
118
+
119
+ ---
120
+
121
+ #### Pattern 1 — Self-Describing Robots/Tools (HIGH VALUE)
122
+
123
+ This is the missing piece for `tool_manifest_plan.md`. Nothing auto-registers today because there is nowhere to register *to* and no class-level metadata to register. agentf's insight: put descriptors at the class level, not in instances.
124
+
125
+ ```ruby
126
+ class MyTool < RobotLab::Tool
127
+ self.description = "Fetch current weather for a location"
128
+ self.tags = [:network, :read_only]
129
+ end
130
+ ```
131
+
132
+ At class-load time, Zeitwerk triggers auto-registration into `RobotLab.tool_registry`. The selector-robot pattern becomes viable without any explicit registration ceremony. Live callable instances stay per-robot; the global registry holds lightweight descriptors only (name + description). This is the v1 the `tool_manifest_plan.md` actually needs — and avoids the MCP auto-registration problem identified in that plan's review notes.
133
+
134
+ Robot subclasses get the same treatment:
135
+ ```ruby
136
+ class SupportBot < RobotLab::Robot
137
+ self.description = "Handles tier-1 customer support"
138
+ self.capabilities = [:search, :ticket_creation]
139
+ end
140
+ ```
141
+
142
+ This also enables the `Installer`-style manifest generation: `RobotLab.tool_registry.summary` produces the compact name+description list the selector robot reasons over.
143
+
144
+ ---
145
+
146
+ #### Patterns 2 + 8 — Contract Enforcement + Policy Boundaries (HIGH VALUE, medium effort)
147
+
148
+ RobotLab has a circuit breaker (`max_tool_rounds`) and an error hierarchy — but no *pre/post validation layer* on execution. As AIA drives RobotLab into production use, this gap is significant.
149
+
150
+ The three modes map cleanly to the dev→prod lifecycle:
151
+ - `advisory` — log violations, don't block (development default)
152
+ - `enforcing` — raise on violation (production default)
153
+ - `off` — no overhead (test default)
154
+
155
+ Policies declared at the Tool class level:
156
+ ```ruby
157
+ class DeleteFileTool < RobotLab::Tool
158
+ policy :ask_first # always prompt user before executing
159
+ end
160
+
161
+ class FormatDriveTool < RobotLab::Tool
162
+ policy :never # contract blocks execution entirely in enforcing mode
163
+ end
164
+ ```
165
+
166
+ The contract wraps `robot.run()` with `before!`/`after!` hooks — checks token budget, validates tool policies, enforces max cost. A `RunConfig` field (`contract: :advisory`) controls the mode and flows through the standard hierarchy. This pairs naturally with the existing `RunConfig` merge semantics and would be the first true safety/governance layer in RobotLab.
167
+
168
+ ---
169
+
170
+ #### Pattern 9 — Workflow Profiles (LOW EFFORT, good discoverability)
171
+
172
+ Networks are currently built by hand each time. A `RobotLab::Profiles` module with named constants would reduce boilerplate and document canonical topologies:
173
+
174
+ ```ruby
175
+ RobotLab::Profiles::CONSENSUS # fan-out to N robots → reconciler
176
+ RobotLab::Profiles::PIPELINE # sequential chain
177
+ RobotLab::Profiles::PARALLEL # concurrent, no synthesis
178
+ RobotLab::Profiles::MCP_FAN_OUT # one robot per MCP server
179
+ ```
180
+
181
+ Each profile is a lambda/factory that takes robots + optional router and returns a configured network. This also gives AIA's `RobotFactory` topologies a canonical home in the library itself rather than application-level code.
182
+
183
+ ---
184
+
185
+ #### Pattern 5 — Eval Framework (MEDIUM EFFORT, high long-term value)
186
+
187
+ RobotLab has 22 example scripts but **zero assertions**. They are demos, not evals. agentf's `prompt.txt + scenario.yml + verify.sh` per scenario is the right shape.
188
+
189
+ For RobotLab the natural form:
190
+ - `evals/scenarios/convergence_basic/` — prompt, expected behavior description, `verify.rb` script
191
+ - `rake eval:run[convergence_basic]` replays against a VCR cassette and asserts postconditions
192
+ - `rake eval:run:all` becomes a regression suite for agent behavior
193
+
194
+ This connects directly to AIA's EDD (Eval-Driven Development) vision and would give confidence before a 1.0 release. The existing VCR/WebMock infrastructure is the right foundation.
195
+
196
+ ---
197
+
198
+ #### Pattern 4 — Deterministic Embedding Fallback (LOW EFFORT)
199
+
200
+ `DocumentStore` hard-requires fastembed — no fallback. On first use it downloads an ONNX model, which is slow and requires a working network. `word_hash` (stemmed TF vectors) already exists in the codebase and is used by `compress_history`, `search_history`, and `Convergence`.
201
+
202
+ A simple degradation path: when fastembed raises `LoadError` or the model is unavailable, `DocumentStore` falls back to `word_hash` cosine similarity with a logged warning. Zero new infrastructure — just wiring what already exists into `DocumentStore#embed`.
203
+
204
+ ---
205
+
206
+ #### Pattern 3 — HITL Confirmation Protocol (LOW VALUE given AskUser)
207
+
208
+ The agentf pattern — return `{ confirmation: true, payload: }` instead of raising, re-invoke with `confirmedWrite: "confirmed"` — is elegant for memory writes that need approval. However, RobotLab already has `AskUser` for the primary HITL use case. This pattern only becomes interesting if RobotLab needs programmatic HITL that doesn't require a terminal (e.g., web apps pausing for user approval via HTTP callback). Not urgent.
209
+
210
+ ---
211
+
212
+ ### Priority Ranking
213
+
214
+ | Priority | Pattern | Effort | Connects To |
215
+ |---|---|---|---|
216
+ | 1 | Self-describing tools/robots (class-level metadata) | Medium | `tool_manifest_plan.md` — makes ToolManifest v1 actionable |
217
+ | 2 | Contract enforcement + Policy boundaries | Medium | Production safety gap; RunConfig integration |
218
+ | 3 | Eval framework | Medium | Long-term regression confidence; AIA EDD |
219
+ | 4 | Workflow profiles | Low | AIA's RobotFactory; discoverability |
220
+ | 5 | DocumentStore word_hash fallback | Low | Dev ergonomics; no ONNX download needed |
221
+
222
+ **Natural weekly pairing:** Pattern 1 (self-describing classes → ToolManifest v1) + Pattern 9 (workflow profiles) form a coherent "discoverability and composability" theme. Patterns 2+8 are the right *next* architectural investment but scope to a separate week.
223
+
224
+ ---
225
+
226
+ ## Comparison to Other Agent Frameworks
227
+
228
+ | Aspect | `agentf` | LangChain (Python) | CrewAI (Python) |
229
+ |---|---|---|---|
230
+ | Language | Ruby | Python | Python |
231
+ | LLM calls | None (delegates to IDE) | Direct | Direct |
232
+ | Agent communication | Shared Redis memory | In-process state | Sequential/hierarchical |
233
+ | Memory | Episodic + semantic (Redis Stack) | Various vector stores | Basic |
234
+ | IDE integration | MCP server (Copilot, OpenCode) | None native | None native |
235
+ | Contract enforcement | 3-mode advisory/enforcing/off | None | None |
236
+ | Self-describing agents | Class-method metadata | No | Role strings in YAML |
237
+ | Eval framework | Black-box shell scripts | Unit tests | Unit tests |
238
+ | TDD enforcement | Built-in (red/green contracts) | None | None |
239
+
240
+ Within Ruby there is essentially no direct equivalent. `ruby-openai` and
241
+ `omniai` handle LLM API calls but have no orchestration. `agentf` is novel in
242
+ the Ruby ecosystem for combining Redis-backed episodic memory, role-specialized
243
+ agent classes, contract enforcement, and an MCP stdio server in one gem.
244
+
245
+ ---
246
+
247
+ ## The Big Takeaway
248
+
249
+ The most instructive thing about `agentf` is its **division of responsibility**:
250
+ the gem owns memory, sequencing, policies, and tool-exposure via MCP — the
251
+ IDE's AI owns inference. That separation means no API keys, no HTTP calls to
252
+ LLM providers, and no model coupling. If building AI-assisted tooling in Ruby,
253
+ that architecture is worth emulating.
data/agents.md ADDED
@@ -0,0 +1,14 @@
1
+ ### Local Agent Context: Repository Root
2
+
3
+ - Start here, then navigate to the closest directory AGENTS.md before coding.
4
+ - Do not operate from root unless necessary.
5
+
6
+ ## Table of Contents
7
+
8
+ - [.architecture/reviews](./.architecture/reviews/AGENTS.md): Access `config.yml` for architecture-related settings.
9
+ - [.github/workflows](./.github/workflows/AGENTS.md): Review `deploy-github-pages.yml` for CI/CD pipeline specifics.
10
+ - [.ruby-lsp](./.ruby-lsp/AGENTS.md): Initialize your environment with `Gemfile` dependencies.
11
+ - [docs](./docs/AGENTS.md): Consult `/docs/api/core/robot.md` for robot-related API documentation.
12
+ - [examples](./examples/AGENTS.md): Explore `14_rusty_circuit/open_mic.rb` for demo scripts in action.
13
+ - [lib/generators/robot_lab](./lib/generators/robot_lab/AGENTS.md): Use `templates/initializer.rb.tt` for custom project setup.
14
+ - [test/robot_lab](./test/robot_lab/AGENTS.md): Implement new tests based on `test_helper.rb` configurations.
@@ -14,10 +14,11 @@ These examples show how to use RobotLab for common scenarios, from simple chatbo
14
14
  | [Multi-Robot Network](multi-robot-network.md) | Customer service with routing |
15
15
  | [Tool Usage](tool-usage.md) | External API integration |
16
16
  | [MCP Server](mcp-server.md) | Creating an MCP tool server |
17
- | [Rails Application](rails-application.md) | Full Rails integration |
18
17
  | [Message Bus](#message-bus) | Bidirectional robot communication with convergence |
19
18
  | [Spawning Robots](#spawning-robots) | Dynamic specialist creation at runtime |
20
19
 
20
+ > **Rails example** — see [robot_lab-rails](https://github.com/MadBomber/robot_lab-rails/blob/main/docs/examples/rails-application.md) for a full Rails integration example.
21
+
21
22
  ## Quick Links
22
23
 
23
24
  ### Simple Examples
@@ -158,7 +159,7 @@ puts result.last_text_content
158
159
 
159
160
  3. Run example:
160
161
  ```bash
161
- ruby examples/basic_chat.rb
162
+ ruby examples/01_simple_robot.rb
162
163
  ```
163
164
 
164
165
  Or use the provided rake tasks:
@@ -168,6 +169,40 @@ bundle exec rake examples:all # Run all examples
168
169
  bundle exec rake examples:run[1] # Run specific example by number
169
170
  ```
170
171
 
172
+ ## Shared Example Setup (`examples/common.rb`)
173
+
174
+ All numbered examples (`01_*.rb` through `34_*.rb`) begin with:
175
+
176
+ ```ruby
177
+ require_relative "common"
178
+ ```
179
+
180
+ `common.rb` handles the shared boilerplate so individual examples stay focused:
181
+
182
+ - **`LLM` hash** — frozen lookup of provider/model pairs accessible as `LLM[:default]`, `LLM[:local]`, `LLM[:anthropic]`. Each entry is a `LlmConfig = Data.define(:provider, :model)` value, so you access the model string as `LLM[:default].model`.
183
+ - **`RubyLLM.configure`** — sets a null logger and `LLM[:default].model` as the `default_model`.
184
+ - **`RobotLab.configure`** — sets a null logger.
185
+ - **Output helpers** — `banner(title)`, `section(title)`, `hr`, and `show_code(ruby_string, label:)` (Rouge-highlighted) for consistent terminal formatting.
186
+
187
+ ## Template Path via direnv
188
+
189
+ Examples that bundle their own `prompts/` directory ship with a `.envrc` file:
190
+
191
+ ```
192
+ examples/.envrc
193
+ examples/14_rusty_circuit/.envrc
194
+ examples/15_memory_network_and_bus/.envrc
195
+ examples/16_writers_room/.envrc
196
+ ```
197
+
198
+ Each sets `ROBOT_LAB_TEMPLATE_PATH` to the local `prompts/` directory when [direnv](https://direnv.net/) is active. `common.rb` also sets this variable as a fallback if `direnv` has not loaded the `.envrc`:
199
+
200
+ ```ruby
201
+ ENV["ROBOT_LAB_TEMPLATE_PATH"] ||= File.join(__dir__, "prompts")
202
+ ```
203
+
204
+ This means examples work correctly whether you run them from the project root with rake tasks or directly from inside the example's own directory.
205
+
171
206
  ## Message Bus
172
207
 
173
208
  Robots can communicate bidirectionally via a message bus, enabling convergence loops and negotiation patterns. This example demonstrates a comedy critic tasking a comedian to generate jokes until one passes:
@@ -31,8 +31,14 @@ RobotLab.config.streaming_enabled #=> true
31
31
  RobotLab.config.development? #=> true/false
32
32
  ```
33
33
 
34
- !!! warning "No configure block"
35
- RobotLab does **not** use a `RobotLab.configure do |config| ... end` pattern. All configuration comes from config files, environment variables, or direct assignment on `RobotLab.config`.
34
+ !!! tip "configure block"
35
+ `RobotLab.configure` yields the config object for block-style setup useful for setting runtime-only attributes like the logger. For static settings (API keys, timeouts, model defaults) prefer config files or environment variables.
36
+
37
+ ```ruby
38
+ RobotLab.configure do |c|
39
+ c.logger = Logger.new(File::NULL) # silence all RobotLab logging
40
+ end
41
+ ```
36
42
 
37
43
  ## Environment Variables
38
44
 
@@ -195,14 +201,21 @@ Default chat parameters applied to all robots unless overridden:
195
201
 
196
202
  ## Runtime-Only Attributes
197
203
 
198
- Some attributes can only be set at runtime, not through config files:
204
+ Some attributes can only be set at runtime, not through config files. Use direct assignment on `RobotLab.config` or the `RobotLab.configure` block:
199
205
 
200
206
  ```ruby
201
- # Logger (defaults to Rails.logger in Rails, or Logger.new($stdout) otherwise)
202
- RobotLab.config.logger = Logger.new(nil) # silence logging
203
- RobotLab.config.logger = Logger.new("robot.log") # log to file
207
+ # Direct assignment
208
+ RobotLab.config.logger = Logger.new(nil) # silence logging
209
+ RobotLab.config.logger = Logger.new("robot.log") # log to file
210
+
211
+ # Block-style configure (equivalent, useful when setting multiple values)
212
+ RobotLab.configure do |c|
213
+ c.logger = Logger.new(File::NULL)
214
+ end
204
215
  ```
205
216
 
217
+ `RobotLab.configure` yields the same `Config` object returned by `RobotLab.config`.
218
+
206
219
  ## Reloading Configuration
207
220
 
208
221
  To reload configuration from all sources:
@@ -361,7 +374,7 @@ effective.temperature #=> 0.9 (overridden)
361
374
  | **LLM** | `model`, `temperature`, `top_p`, `top_k`, `max_tokens`, `presence_penalty`, `frequency_penalty`, `stop` |
362
375
  | **Tools** | `mcp`, `tools` |
363
376
  | **Callbacks** | `on_tool_call`, `on_tool_result` |
364
- | **Infrastructure** | `bus`, `enable_cache`, `max_tool_rounds`, `token_budget`, `ractor_pool_size`, `max_concurrent_robots` |
377
+ | **Infrastructure** | `bus`, `enable_cache`, `max_tool_rounds`, `token_budget`, `ractor_pool_size`, `max_concurrent_robots`, `doom_loop_threshold`, `auto_compact`, `compact_threshold` |
365
378
 
366
379
  ### RunConfig vs RobotLab.config
367
380
 
data/docs/guides/index.md CHANGED
@@ -40,21 +40,11 @@ If you're new to RobotLab, start here:
40
40
 
41
41
  - [:octicons-pulse-24: **Observability & Safety**](observability.md)
42
42
 
43
- Token tracking, circuit breakers, and learning accumulation
43
+ Token tracking, circuit breakers, doom loop detection, auto compaction, and learning accumulation
44
44
 
45
- - [:material-cpu-64-bit: **Ractor Parallelism**](ractor-parallelism.md)
45
+ - [:octicons-search-24: **Knowledge & Retrieval**](knowledge.md)
46
46
 
47
- True CPU parallelism for tools and robot pipelines via Ruby Ractors
48
-
49
- </div>
50
-
51
- ## Framework Integration
52
-
53
- <div class="grid cards" markdown>
54
-
55
- - [:material-language-ruby:{ .lg } **Rails Integration**](rails-integration.md)
56
-
57
- Use RobotLab in Ruby on Rails applications
47
+ Chat history search and embedding-based document store for RAG workflows
58
48
 
59
49
  </div>
60
50
 
@@ -68,6 +58,16 @@ If you're new to RobotLab, start here:
68
58
  | [MCP Integration](mcp-integration.md) | External tool servers | 10 min |
69
59
  | [Streaming](streaming.md) | Real-time responses | 5 min |
70
60
  | [Memory](memory.md) | Shared data store | 5 min |
71
- | [Rails Integration](rails-integration.md) | Rails application setup | 15 min |
72
- | [Observability & Safety](observability.md) | Token tracking, circuit breaker, learning loop | 10 min |
73
- | [Ractor Parallelism](ractor-parallelism.md) | CPU-parallel tools and robot pipelines | 15 min |
61
+ | [Observability & Safety](observability.md) | Token tracking, circuit breaker, doom loop detection, auto compaction, learning loop | 10 min |
62
+ | [Knowledge & Retrieval](knowledge.md) | Chat history search and embedding-based document store (RAG) | 10 min |
63
+
64
+ ## Extension Gems
65
+
66
+ Additional capabilities are available as separate gems:
67
+
68
+ | Gem | Description | Docs |
69
+ |-----|-------------|------|
70
+ | [robot_lab-rails](https://github.com/MadBomber/robot_lab-rails) | Rails generators, background jobs, Turbo Stream broadcasting | [Rails Integration guide](https://github.com/MadBomber/robot_lab-rails/blob/main/docs/guides/rails-integration.md) |
71
+ | [robot_lab-ractor](https://github.com/MadBomber/robot_lab-ractor) | True CPU parallelism for tools and robot pipelines via Ruby Ractors | [Ractor Parallelism guide](https://github.com/MadBomber/robot_lab-ractor/blob/main/docs/guides/ractor-parallelism.md) |
72
+ | [robot_lab-durable](https://github.com/MadBomber/robot_lab-durable) | Cross-session knowledge persistence with YAML-backed storage | [robot_lab-durable README](https://github.com/MadBomber/robot_lab-durable) |
73
+ | [robot_lab-document_store](https://github.com/MadBomber/robot_lab-document_store) | Embedding-based semantic document search via fastembed | [robot_lab-document_store README](https://github.com/MadBomber/robot_lab-document_store) |
@@ -171,7 +171,13 @@ result = robot.run("Use the following context:\n#{context}\n\nQuestion: #{user_q
171
171
 
172
172
  ### Dependency
173
173
 
174
- `fastembed` is a core RobotLab dependency no optional gem required. The ONNX model is downloaded on first use.
174
+ The embedding-based document store requires the [`robot_lab-document_store`](https://github.com/MadBomber/robot_lab-document_store) extension gem. Add it to your Gemfile:
175
+
176
+ ```ruby
177
+ gem "robot_lab-document_store"
178
+ ```
179
+
180
+ This gem bundles `fastembed` for ONNX-based embeddings. The `BAAI/bge-small-en-v1.5` model (~23 MB) is downloaded on first use and cached in `~/.cache/fastembed/`. Without `robot_lab-document_store` loaded, calling `memory.store_document` or `memory.search_documents` raises `RobotLab::DependencyError`.
175
181
 
176
182
  ---
177
183