robot_lab 0.3.0 → 0.3.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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +1 -1
  4. data/lib/robot_lab/mcp/transports/streamable_http.rb +1 -1
  5. data/lib/robot_lab/version.rb +1 -1
  6. metadata +3 -253
  7. data/.architecture/AGENTS.md +0 -32
  8. data/.architecture/config.yml +0 -8
  9. data/.architecture/members.yml +0 -60
  10. data/.architecture/reviews/feature-free-will.md +0 -490
  11. data/.architecture/reviews/overall-codebase.md +0 -427
  12. data/.claude/settings.local.json +0 -57
  13. data/.codex/config.toml +0 -2
  14. data/.envrc +0 -6
  15. data/.github/workflows/deploy-github-pages.yml +0 -52
  16. data/.irbrc +0 -6
  17. data/.loki +0 -65
  18. data/.quality/reek_baseline.txt +0 -43
  19. data/.rubocop.yml +0 -10
  20. data/Archspec.rb +0 -44
  21. data/CLAUDE.md +0 -141
  22. data/COMMITS.md +0 -196
  23. data/Rakefile +0 -193
  24. data/_typos.toml +0 -21
  25. data/agent2agent_review.md +0 -192
  26. data/agentf_improvements.md +0 -253
  27. data/agents.md +0 -14
  28. data/docs/api/core/index.md +0 -147
  29. data/docs/api/core/memory.md +0 -578
  30. data/docs/api/core/network.md +0 -553
  31. data/docs/api/core/result.md +0 -211
  32. data/docs/api/core/robot.md +0 -1667
  33. data/docs/api/core/state.md +0 -145
  34. data/docs/api/core/tool.md +0 -520
  35. data/docs/api/errors.md +0 -323
  36. data/docs/api/hooks.md +0 -469
  37. data/docs/api/index.md +0 -137
  38. data/docs/api/mcp/client.md +0 -387
  39. data/docs/api/mcp/index.md +0 -267
  40. data/docs/api/mcp/server.md +0 -252
  41. data/docs/api/mcp/transports.md +0 -339
  42. data/docs/api/messages/index.md +0 -126
  43. data/docs/api/messages/text-message.md +0 -170
  44. data/docs/api/messages/tool-call-message.md +0 -206
  45. data/docs/api/messages/tool-result-message.md +0 -242
  46. data/docs/api/messages/user-message.md +0 -232
  47. data/docs/api/skills.md +0 -423
  48. data/docs/api/streaming/context.md +0 -280
  49. data/docs/api/streaming/events.md +0 -185
  50. data/docs/api/streaming/index.md +0 -156
  51. data/docs/api/support.md +0 -846
  52. data/docs/architecture/core-concepts.md +0 -575
  53. data/docs/architecture/index.md +0 -252
  54. data/docs/architecture/message-flow.md +0 -366
  55. data/docs/architecture/network-orchestration.md +0 -478
  56. data/docs/architecture/robot-execution.md +0 -396
  57. data/docs/architecture/state-management.md +0 -410
  58. data/docs/assets/css/custom.css +0 -56
  59. data/docs/assets/images/robot_lab.jpg +0 -0
  60. data/docs/concepts.md +0 -641
  61. data/docs/examples/basic-chat.md +0 -258
  62. data/docs/examples/index.md +0 -425
  63. data/docs/examples/mcp-server.md +0 -403
  64. data/docs/examples/multi-robot-network.md +0 -476
  65. data/docs/examples/tool-usage.md +0 -468
  66. data/docs/getting-started/configuration.md +0 -645
  67. data/docs/getting-started/index.md +0 -56
  68. data/docs/getting-started/installation.md +0 -197
  69. data/docs/getting-started/quick-start.md +0 -293
  70. data/docs/guides/building-robots.md +0 -1187
  71. data/docs/guides/creating-networks.md +0 -736
  72. data/docs/guides/hooks.md +0 -1206
  73. data/docs/guides/index.md +0 -78
  74. data/docs/guides/knowledge.md +0 -219
  75. data/docs/guides/mcp-integration.md +0 -740
  76. data/docs/guides/memory.md +0 -458
  77. data/docs/guides/observability.md +0 -733
  78. data/docs/guides/streaming.md +0 -323
  79. data/docs/guides/using-tools.md +0 -780
  80. data/docs/index.md +0 -280
  81. data/docs/superpowers/plans/2026-05-06-agentskills.md +0 -1303
  82. data/docs/superpowers/specs/2026-05-06-agentskills-design.md +0 -247
  83. data/examples/.envrc +0 -3
  84. data/examples/01_simple_robot.rb +0 -31
  85. data/examples/02_tools.rb +0 -109
  86. data/examples/03_network.rb +0 -118
  87. data/examples/04_mcp.rb +0 -217
  88. data/examples/05_streaming.rb +0 -137
  89. data/examples/06_prompt_templates.rb +0 -325
  90. data/examples/07_network_memory.rb +0 -313
  91. data/examples/08_llm_config.rb +0 -162
  92. data/examples/09_chaining.rb +0 -251
  93. data/examples/10_memory.rb +0 -315
  94. data/examples/11_network_introspection.rb +0 -239
  95. data/examples/12_message_bus.rb +0 -67
  96. data/examples/13_spawn.rb +0 -85
  97. data/examples/14_rusty_circuit/.envrc +0 -1
  98. data/examples/14_rusty_circuit/.gitignore +0 -1
  99. data/examples/14_rusty_circuit/README.md +0 -1
  100. data/examples/14_rusty_circuit/comic.rb +0 -149
  101. data/examples/14_rusty_circuit/display.rb +0 -217
  102. data/examples/14_rusty_circuit/heckler.rb +0 -65
  103. data/examples/14_rusty_circuit/open_mic.rb +0 -132
  104. data/examples/14_rusty_circuit/prompts/open_mic_comic.md +0 -20
  105. data/examples/14_rusty_circuit/prompts/open_mic_heckler.md +0 -23
  106. data/examples/14_rusty_circuit/prompts/open_mic_scout.md +0 -20
  107. data/examples/14_rusty_circuit/scout.rb +0 -165
  108. data/examples/14_rusty_circuit/show.log +0 -234
  109. data/examples/15_memory_network_and_bus/.envrc +0 -1
  110. data/examples/15_memory_network_and_bus/README.md +0 -66
  111. data/examples/15_memory_network_and_bus/editor_in_chief.rb +0 -24
  112. data/examples/15_memory_network_and_bus/editorial_pipeline.rb +0 -213
  113. data/examples/15_memory_network_and_bus/linux_writer.rb +0 -80
  114. data/examples/15_memory_network_and_bus/os_editor.rb +0 -48
  115. data/examples/15_memory_network_and_bus/os_writer.rb +0 -49
  116. data/examples/15_memory_network_and_bus/output/combined_article.md +0 -11
  117. data/examples/15_memory_network_and_bus/output/final_article.md +0 -8
  118. data/examples/15_memory_network_and_bus/output/linux_draft.md +0 -7
  119. data/examples/15_memory_network_and_bus/output/mac_draft.md +0 -7
  120. data/examples/15_memory_network_and_bus/output/memory.json +0 -13
  121. data/examples/15_memory_network_and_bus/output/revision_1.md +0 -29
  122. data/examples/15_memory_network_and_bus/output/revision_2.md +0 -50
  123. data/examples/15_memory_network_and_bus/output/revision_3.md +0 -8
  124. data/examples/15_memory_network_and_bus/output/windows_draft.md +0 -7
  125. data/examples/15_memory_network_and_bus/prompts/os_advocate.md +0 -13
  126. data/examples/15_memory_network_and_bus/prompts/os_chief.md +0 -13
  127. data/examples/15_memory_network_and_bus/prompts/os_editor.md +0 -13
  128. data/examples/16_writers_room/.envrc +0 -1
  129. data/examples/16_writers_room/display.rb +0 -158
  130. data/examples/16_writers_room/output/.gitignore +0 -4
  131. data/examples/16_writers_room/output/README.md +0 -69
  132. data/examples/16_writers_room/output/opus_001.md +0 -263
  133. data/examples/16_writers_room/output/opus_001_notes.log +0 -470
  134. data/examples/16_writers_room/output/opus_002.md +0 -245
  135. data/examples/16_writers_room/output/opus_002_notes.log +0 -546
  136. data/examples/16_writers_room/output/opus_002_screenplay.md +0 -7989
  137. data/examples/16_writers_room/output/opus_002_screenplay_notes.md +0 -993
  138. data/examples/16_writers_room/prompts/screenplay_writer.md +0 -66
  139. data/examples/16_writers_room/prompts/writer.md +0 -37
  140. data/examples/16_writers_room/room.rb +0 -186
  141. data/examples/16_writers_room/tools.rb +0 -173
  142. data/examples/16_writers_room/writer.rb +0 -121
  143. data/examples/16_writers_room/writers_room.rb +0 -256
  144. data/examples/17_skills.rb +0 -234
  145. data/examples/18_rails/.envrc +0 -3
  146. data/examples/18_rails/.gitignore +0 -5
  147. data/examples/18_rails/Gemfile +0 -11
  148. data/examples/18_rails/README.md +0 -67
  149. data/examples/18_rails/Rakefile +0 -4
  150. data/examples/18_rails/app/controllers/application_controller.rb +0 -4
  151. data/examples/18_rails/app/controllers/chat_controller.rb +0 -50
  152. data/examples/18_rails/app/jobs/application_job.rb +0 -4
  153. data/examples/18_rails/app/jobs/robot_run_job.rb +0 -25
  154. data/examples/18_rails/app/models/application_record.rb +0 -5
  155. data/examples/18_rails/app/models/robot_lab_result.rb +0 -36
  156. data/examples/18_rails/app/models/robot_lab_thread.rb +0 -23
  157. data/examples/18_rails/app/robots/chat_robot.rb +0 -25
  158. data/examples/18_rails/app/tools/time_tool.rb +0 -9
  159. data/examples/18_rails/app/views/chat/_user_message.html.erb +0 -1
  160. data/examples/18_rails/app/views/chat/index.html.erb +0 -67
  161. data/examples/18_rails/app/views/layouts/application.html.erb +0 -49
  162. data/examples/18_rails/bin/dev +0 -7
  163. data/examples/18_rails/bin/rails +0 -6
  164. data/examples/18_rails/bin/setup +0 -15
  165. data/examples/18_rails/config/application.rb +0 -33
  166. data/examples/18_rails/config/cable.yml +0 -2
  167. data/examples/18_rails/config/database.yml +0 -5
  168. data/examples/18_rails/config/environment.rb +0 -4
  169. data/examples/18_rails/config/initializers/robot_lab.rb +0 -11
  170. data/examples/18_rails/config/routes.rb +0 -6
  171. data/examples/18_rails/config.ru +0 -4
  172. data/examples/18_rails/db/migrate/001_create_robot_lab_tables.rb +0 -32
  173. data/examples/19_token_tracking.rb +0 -138
  174. data/examples/20_circuit_breaker.rb +0 -147
  175. data/examples/21_learning_loop.rb +0 -181
  176. data/examples/22_context_compression.rb +0 -172
  177. data/examples/23_convergence.rb +0 -133
  178. data/examples/24_structured_delegation.rb +0 -151
  179. data/examples/25_history_search/conversation.jsonl +0 -30
  180. data/examples/25_history_search.rb +0 -133
  181. data/examples/26_document_store/api_versioning_adr.md +0 -52
  182. data/examples/26_document_store/incident_postmortem.md +0 -46
  183. data/examples/26_document_store/postgres_runbook.md +0 -49
  184. data/examples/26_document_store/redis_caching_guide.md +0 -48
  185. data/examples/26_document_store/sidekiq_guide.md +0 -51
  186. data/examples/26_document_store.rb +0 -140
  187. data/examples/27_incident_response/README.md +0 -65
  188. data/examples/27_incident_response/incident_response.rb +0 -261
  189. data/examples/28_mcp_discovery.rb +0 -113
  190. data/examples/29_ractor_tools.rb +0 -240
  191. data/examples/30_ractor_network.rb +0 -252
  192. data/examples/31_launch_assessment.rb +0 -246
  193. data/examples/32_newsletter_reader.rb +0 -193
  194. data/examples/33_stock_generator.rb +0 -80
  195. data/examples/33_stock_predictor.rb +0 -327
  196. data/examples/34_agentskills.rb +0 -76
  197. data/examples/35_hooks.rb +0 -266
  198. data/examples/README.md +0 -550
  199. data/examples/common.rb +0 -180
  200. data/examples/prompts/assistant.md +0 -5
  201. data/examples/prompts/audit_trail.md +0 -8
  202. data/examples/prompts/billing.md +0 -10
  203. data/examples/prompts/classifier.md +0 -7
  204. data/examples/prompts/comedian.md +0 -6
  205. data/examples/prompts/comedy_critic.md +0 -10
  206. data/examples/prompts/configurable.md +0 -9
  207. data/examples/prompts/dispatcher.md +0 -12
  208. data/examples/prompts/entity_extractor.md +0 -14
  209. data/examples/prompts/escalation.md +0 -42
  210. data/examples/prompts/frontmatter_mcp_test.md +0 -9
  211. data/examples/prompts/frontmatter_named_test.md +0 -5
  212. data/examples/prompts/frontmatter_tools_test.md +0 -6
  213. data/examples/prompts/general.md +0 -7
  214. data/examples/prompts/github_assistant.md +0 -14
  215. data/examples/prompts/helper.md +0 -4
  216. data/examples/prompts/incident_responder.md +0 -18
  217. data/examples/prompts/keyword_extractor.md +0 -11
  218. data/examples/prompts/llm_config_demo.md +0 -20
  219. data/examples/prompts/order_support.md +0 -35
  220. data/examples/prompts/os_advocate.md +0 -13
  221. data/examples/prompts/os_chief.md +0 -13
  222. data/examples/prompts/os_editor.md +0 -13
  223. data/examples/prompts/parameterized_main_test.md +0 -6
  224. data/examples/prompts/pii_redactor.md +0 -7
  225. data/examples/prompts/product_support.md +0 -37
  226. data/examples/prompts/runbook_protocol.md +0 -12
  227. data/examples/prompts/sentiment_analyzer.md +0 -12
  228. data/examples/prompts/skill_a_test.md +0 -4
  229. data/examples/prompts/skill_b_test.md +0 -4
  230. data/examples/prompts/skill_config_test.md +0 -5
  231. data/examples/prompts/skill_cycle_a_test.md +0 -6
  232. data/examples/prompts/skill_cycle_b_test.md +0 -6
  233. data/examples/prompts/skill_description_test.md +0 -4
  234. data/examples/prompts/skill_leaf_test.md +0 -4
  235. data/examples/prompts/skill_nested_test.md +0 -6
  236. data/examples/prompts/skill_refs_main_test.md +0 -6
  237. data/examples/prompts/skill_self_ref_test.md +0 -6
  238. data/examples/prompts/skill_with_mcp_test.md +0 -9
  239. data/examples/prompts/skill_with_params_test.md +0 -6
  240. data/examples/prompts/skill_with_robot_name_test.md +0 -5
  241. data/examples/prompts/skill_with_tools_test.md +0 -6
  242. data/examples/prompts/sre_compliance.md +0 -10
  243. data/examples/prompts/structured_output.md +0 -7
  244. data/examples/prompts/synthesizer.md +0 -17
  245. data/examples/prompts/technical.md +0 -10
  246. data/examples/prompts/template_with_skills_test.md +0 -6
  247. data/examples/prompts/triage.md +0 -22
  248. data/examples/ruboruby.md +0 -423
  249. data/examples/run_all.rb +0 -60
  250. data/examples/xyzzy.rb +0 -97
  251. data/logfile +0 -8
  252. data/mkdocs.yml +0 -209
  253. data/robot_concurrency.md +0 -38
  254. data/simple_acp_review.md +0 -298
  255. data/temp.md +0 -6
  256. data/tool_manifest_plan.md +0 -155
@@ -1,645 +0,0 @@
1
- # Configuration
2
-
3
- RobotLab uses a layered configuration system powered by [MywayConfig](https://github.com/MadBomber/myway_config). Configuration is loaded automatically from multiple sources with no block-style `configure` method required.
4
-
5
- ## How Configuration Works
6
-
7
- Configuration values are loaded in priority order (lowest to highest):
8
-
9
- 1. **Bundled defaults** -- `lib/robot_lab/config/defaults.yml` (shipped with the gem)
10
- 2. **Environment-specific overrides** -- `development`, `test`, or `production` sections in defaults.yml
11
- 3. **User config file** -- `~/.config/robot_lab/robot_lab.yml`
12
- 4. **Project config file** -- `./config/robot_lab.yml`
13
- 5. **Environment variables** -- `ROBOT_LAB_*` prefix
14
- 6. **Runtime attributes** -- e.g., `RobotLab.config.logger = ...`
15
-
16
- Higher-priority sources override lower-priority ones. You only need to set the values you want to change.
17
-
18
- > [!IMPORTANT]
19
- > The user config file is `~/.config/robot_lab/**robot_lab**.yml` — the filename
20
- > repeats the application name. `~/.config/robot_lab/config.yml` is **never
21
- > read**, and RobotLab gives no warning when it is present but ignored.
22
-
23
- ## Accessing Configuration
24
-
25
- Use `RobotLab.config` to access the configuration object:
26
-
27
- ```ruby
28
- # Access nested values with dot notation
29
- RobotLab.config.ruby_llm.model #=> "claude-sonnet-4"
30
- RobotLab.config.ruby_llm.anthropic_api_key #=> "sk-ant-..."
31
- RobotLab.config.ruby_llm.request_timeout #=> 120
32
- RobotLab.config.template_path #=> nil (auto-detected)
33
-
34
- # Check the environment
35
- RobotLab.config.development? #=> true/false
36
- ```
37
-
38
- !!! tip "configure block"
39
- `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.
40
-
41
- ```ruby
42
- RobotLab.configure do |c|
43
- c.logger = Logger.new(File::NULL) # silence all RobotLab logging
44
- end
45
- ```
46
-
47
- ## Environment Variables
48
-
49
- Environment variables use the `ROBOT_LAB_` prefix. Use double underscores (`__`) for nested values:
50
-
51
- ```bash
52
- # Top-level settings
53
- export ROBOT_LAB_TEMPLATE_PATH=prompts
54
-
55
- # Nested ruby_llm settings (note the double underscore)
56
- export ROBOT_LAB_RUBY_LLM__MODEL=claude-sonnet-4
57
- export ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY=sk-ant-...
58
- export ROBOT_LAB_RUBY_LLM__OPENAI_API_KEY=sk-...
59
- export ROBOT_LAB_RUBY_LLM__GEMINI_API_KEY=...
60
- export ROBOT_LAB_RUBY_LLM__REQUEST_TIMEOUT=180
61
- export ROBOT_LAB_RUBY_LLM__MAX_RETRIES=5
62
- ```
63
-
64
- The double underscore convention maps to nested YAML structure:
65
-
66
- ```
67
- ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY --> ruby_llm.anthropic_api_key
68
- ROBOT_LAB_RUBY_LLM__MODEL --> ruby_llm.model
69
- ROBOT_LAB_TEMPLATE_PATH --> template_path
70
- ```
71
-
72
- > [!WARNING]
73
- > **Nested values arrive as Strings.** Only top-level keys are type-coerced.
74
- > With `ROBOT_LAB_RUBY_LLM__REQUEST_TIMEOUT=180` set,
75
- > `RobotLab.config.ruby_llm.request_timeout` returns the String `"180"`, not the
76
- > Integer `180`. If a numeric nested setting matters to your code, set it in a
77
- > config file instead, or coerce it yourself with `.to_i` / `.to_f`.
78
-
79
- ## Config Files
80
-
81
- > [!WARNING]
82
- > **A `defaults:` wrapper is always ignored in your own files.** The `defaults:`
83
- > key you see inside the gem's bundled `lib/robot_lab/config/defaults.yml` applies
84
- > **only to that bundled file**. Wrap your own settings in it and every value
85
- > silently falls back to the default — no error, no warning.
86
- >
87
- > ```yaml
88
- > # WRONG — silently ignored in a user or project config file
89
- > defaults:
90
- > template_path: prompts
91
- >
92
- > # RIGHT
93
- > template_path: prompts
94
- > ```
95
- >
96
- > Sections named for the **current environment** (`development:`, `test:`,
97
- > `production:`) are a different matter, and the two files disagree:
98
- >
99
- > | File | Flat keys | `development:` section |
100
- > |------|-----------|------------------------|
101
- > | `~/.config/robot_lab/robot_lab.yml` | honoured | honoured |
102
- > | `./config/robot_lab.yml` (no Rails) | honoured | ignored |
103
- > | `./config/robot_lab.yml` (under Rails) | **ignored** | **honoured** |
104
- >
105
- > The user file checks for a section matching the current environment and falls
106
- > back to the file root, so both forms work. The project file is read by
107
- > anyway_config, which only treats it as environmental once
108
- > `Anyway::Settings.current_environment` is set — which is precisely what Rails
109
- > does (it sets it to `Rails.env`). See [Rails Integration](#rails-integration).
110
-
111
- ### Project Config
112
-
113
- Create `./config/robot_lab.yml` in your project root. Outside Rails, write the
114
- keys at the top level (under Rails they must be nested under the environment name
115
- instead — see [Rails Integration](#rails-integration)):
116
-
117
- ```yaml title="config/robot_lab.yml"
118
- ruby_llm:
119
- anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>
120
- model: claude-sonnet-4
121
- request_timeout: 120
122
- max_retries: 3
123
- log_level: info
124
-
125
- template_path: prompts
126
- ```
127
-
128
- > [!NOTE]
129
- > **ERB works here, and only here.** The project config file is read through ERB,
130
- > so `<%= ENV['ANTHROPIC_API_KEY'] %>` is expanded before the YAML is parsed. The
131
- > user config file described below is **not** — see the warning there.
132
-
133
- > [!WARNING]
134
- > **No YAML symbols in the project config file.** It is parsed with an empty
135
- > permitted-classes list, so `log_level: :info` raises
136
- > `Psych::DisallowedClass: Tried to load unspecified class: Symbol` and your
137
- > application fails to boot. Write the plain string `log_level: info`. (Symbols
138
- > *are* permitted in the bundled `defaults.yml` and in the user config file,
139
- > which is why you will see `:debug` there.)
140
-
141
- ### User Config
142
-
143
- Create `~/.config/robot_lab/robot_lab.yml` for personal defaults that apply
144
- across all your projects. Keys go at the top level here too:
145
-
146
- ```yaml title="~/.config/robot_lab/robot_lab.yml"
147
- ruby_llm:
148
- model: claude-sonnet-4
149
- request_timeout: 120
150
- ```
151
-
152
- > [!WARNING]
153
- > **Do not put ERB in the user config file.** It is parsed with
154
- > `YAML.safe_load` and never passed through ERB, so
155
- > `anthropic_api_key: <%= ENV['ANTHROPIC_API_KEY'] %>` is stored as the literal
156
- > nine-character-plus string `"<%= ENV['ANTHROPIC_API_KEY'] %>"` and sent to the
157
- > provider as your API key. Put secrets in environment variables
158
- > (`ANTHROPIC_API_KEY` or `ROBOT_LAB_RUBY_LLM__ANTHROPIC_API_KEY`), or in the
159
- > project config file where ERB is evaluated.
160
-
161
- > [!NOTE]
162
- > The user config file honours **both** forms: flat keys at the root, or a
163
- > top-level section named for the current environment (`development:`, `test:`,
164
- > `production:`). The loader looks for the environment section first and falls back
165
- > to the root. Only `defaults:` is ignored here.
166
-
167
- ## Configuration Reference
168
-
169
- ### Core Settings
170
-
171
- | Key | Default | Description |
172
- |-----|---------|-------------|
173
- | `template_path` | `null` (auto-detected) | Directory for prompt templates |
174
- | `mcp` | `:none` | Global MCP server configuration |
175
- | `tools` | `:none` | Global tool allowlist |
176
- | `sandbox.*` | see below | Skill-script confinement ceiling |
177
-
178
- > [!WARNING]
179
- > **Reserved / not implemented.** `defaults.yml` also ships `max_iterations`,
180
- > `max_tool_iterations`, `streaming_enabled`, and an entire `chat:` tree
181
- > (`chat.with_model`, `chat.with_temperature`, `chat.with_tools`,
182
- > `chat.with_params.*`). These keys resolve — `RobotLab.config.max_iterations`
183
- > returns `10` — but **nothing in the library reads them**. Setting them has zero
184
- > effect. They are placeholders; do not build on them.
185
- >
186
- > The real equivalents are:
187
- >
188
- > | Dead key | Use instead |
189
- > |----------|-------------|
190
- > | `max_tool_iterations` | `max_tool_rounds:` on a robot or `RunConfig` |
191
- > | `streaming_enabled` | `on_content:` callback, or a block passed to `run` |
192
- > | `chat.with_temperature` | `temperature:` on a robot or `RunConfig` |
193
- > | `chat.with_params.*` | `top_p:` / `max_tokens:` / etc. on a robot or `RunConfig` |
194
- > | `max_iterations` | no equivalent — networks are bounded by their task graph |
195
-
196
- ### RubyLLM Settings (`ruby_llm:` section)
197
-
198
- All settings under the `ruby_llm:` key are applied to `RubyLLM.configure` automatically on startup.
199
-
200
- #### Provider API Keys
201
-
202
- | Key | Description |
203
- |-----|-------------|
204
- | `ruby_llm.anthropic_api_key` | Anthropic Claude API key |
205
- | `ruby_llm.openai_api_key` | OpenAI API key |
206
- | `ruby_llm.gemini_api_key` | Google Gemini API key |
207
- | `ruby_llm.deepseek_api_key` | DeepSeek API key |
208
- | `ruby_llm.mistral_api_key` | Mistral API key |
209
- | `ruby_llm.openrouter_api_key` | OpenRouter API key |
210
- | `ruby_llm.bedrock_api_key` | AWS Bedrock access key |
211
- | `ruby_llm.bedrock_secret_key` | AWS Bedrock secret key |
212
- | `ruby_llm.bedrock_region` | AWS Bedrock region |
213
- | `ruby_llm.xai_api_key` | xAI (Grok) API key |
214
-
215
- #### Model Defaults
216
-
217
- | Key | Default | Description |
218
- |-----|---------|-------------|
219
- | `ruby_llm.model` | `claude-sonnet-4` | Default model for robots that do not set `model:` |
220
- | `ruby_llm.default_model` | `null` | RubyLLM default model override |
221
- | `ruby_llm.default_embedding_model` | `null` | Default embedding model |
222
- | `ruby_llm.default_image_model` | `null` | Default image model |
223
-
224
- > [!NOTE]
225
- > `defaults.yml` also carries `ruby_llm.provider: :anthropic` and
226
- > `ruby_llm.assume_model_exists: false`, but neither is read. A robot's provider
227
- > comes from its own `provider:` keyword argument, and `assume_model_exists` is
228
- > derived from whether that argument was given. Model ids must be full RubyLLM
229
- > ids — an unknown id raises `RubyLLM::ModelNotFoundError` when the robot is
230
- > constructed.
231
-
232
- #### Connection Settings
233
-
234
- | Key | Default | Description |
235
- |-----|---------|-------------|
236
- | `ruby_llm.request_timeout` | `120` | Request timeout in seconds |
237
- | `ruby_llm.max_retries` | `3` | Maximum retry attempts |
238
- | `ruby_llm.retry_interval` | `1` | Seconds between retries |
239
- | `ruby_llm.retry_backoff_factor` | `2` | Exponential backoff factor |
240
- | `ruby_llm.http_proxy` | `null` | HTTP proxy URL |
241
-
242
- #### Provider Endpoints (self-hosted models)
243
-
244
- | Key | Description |
245
- |-----|-------------|
246
- | `ruby_llm.openai_api_base` | Custom OpenAI-compatible endpoint |
247
- | `ruby_llm.gemini_api_base` | Custom Gemini endpoint |
248
- | `ruby_llm.ollama_api_base` | Ollama endpoint (e.g., `http://localhost:11434`) |
249
- | `ruby_llm.gpustack_api_base` | GPUStack endpoint |
250
-
251
- #### Logging
252
-
253
- | Key | Default | Description |
254
- |-----|---------|-------------|
255
- | `ruby_llm.log_file` | `null` | Path to log file |
256
- | `ruby_llm.log_level` | `:info` | Log level (`:debug`, `:info`, `:warn`, `:error`) |
257
- | `ruby_llm.log_stream_debug` | `false` | Log streaming debug output |
258
-
259
- ### Chat Configuration (`chat:` section) — not implemented
260
-
261
- The `chat:` tree in `defaults.yml` (`chat.with_temperature`,
262
- `chat.with_params.top_p`, `chat.with_params.max_tokens`, `chat.with_tools`, …)
263
- is **reserved and has no consumers**. Values set there are parsed and then
264
- ignored.
265
-
266
- To set LLM parameters globally, pass a `RunConfig` to each robot, or set them per
267
- robot with constructor keyword arguments:
268
-
269
- ```ruby
270
- robot = RobotLab.build(
271
- name: "bot",
272
- system_prompt: "You are helpful.",
273
- temperature: 0.7,
274
- max_tokens: 2000,
275
- top_p: 0.9
276
- )
277
- ```
278
-
279
- ### Skill-Script Sandboxing (`sandbox:` section)
280
-
281
- Core declares this config schema but has no sandboxing behavior of its own — enforcement
282
- lives in the optional [`robot_lab-sandbox`](https://github.com/MadBomber/robot_lab-sandbox)
283
- gem. Without it, skill scripts always run unconfined regardless of these values; requiring
284
- it installs a `RobotLab::ScriptTool.executor` that honors them:
285
-
286
- | Key | Default | Description |
287
- |-----|---------|-------------|
288
- | `sandbox.enabled` | `false` | Turn on OS-level confinement for skill scripts |
289
- | `sandbox.fs_read` | `["."]` | Ceiling: paths any skill script may read (relative to cwd) |
290
- | `sandbox.fs_write` | `[]` | Ceiling: paths any skill script may write |
291
- | `sandbox.network` | `false` | Ceiling: whether any skill script may use the network |
292
- | `sandbox.timeout` | `60` | Ceiling: max seconds a skill script may run |
293
-
294
- These are a **ceiling**, not a grant — the actual permissions a script runs with are the intersection of this ceiling and what the individual SKILL.md declares for itself. See [Skill Scripts and Sandboxing](../guides/using-tools.md#skill-scripts-and-sandboxing) for how the two combine and which platforms actually enforce confinement.
295
-
296
- ## Runtime-Only Attributes
297
-
298
- Some attributes can only be set at runtime, not through config files. Use direct assignment on `RobotLab.config` or the `RobotLab.configure` block:
299
-
300
- ```ruby
301
- # Direct assignment
302
- RobotLab.config.logger = Logger.new(nil) # silence logging
303
- RobotLab.config.logger = Logger.new("robot.log") # log to file
304
-
305
- # Block-style configure (equivalent, useful when setting multiple values)
306
- RobotLab.configure do |c|
307
- c.logger = Logger.new(File::NULL)
308
- end
309
- ```
310
-
311
- `RobotLab.configure` yields the same `Config` object returned by `RobotLab.config`.
312
-
313
- ## Reloading Configuration
314
-
315
- To reload configuration from all sources:
316
-
317
- ```ruby
318
- RobotLab.reload_config!
319
- ```
320
-
321
- This clears the cached config and reloads from all sources on next access.
322
-
323
- ## Environment-Specific Configuration
324
-
325
- The `defaults.yml` shipped with RobotLab includes environment-specific overrides.
326
- This is what the gem actually ships:
327
-
328
- === "Development"
329
-
330
- ```yaml
331
- development:
332
- ruby_llm:
333
- log_level: :debug
334
- ```
335
-
336
- === "Test"
337
-
338
- ```yaml
339
- test:
340
- max_iterations: 3 # reserved, no effect
341
- streaming_enabled: false # reserved, no effect
342
- ruby_llm:
343
- model: claude-3-haiku-20240307
344
- request_timeout: 30
345
- max_retries: 1
346
- log_level: :warn
347
- ```
348
-
349
- === "Production"
350
-
351
- ```yaml
352
- production:
353
- streaming_enabled: false # reserved, no effect
354
- max_iterations: 20 # reserved, no effect
355
- ruby_llm:
356
- request_timeout: 180
357
- max_retries: 5
358
- log_level: :warn
359
- ```
360
-
361
- The current environment is determined automatically (via `RAILS_ENV`, `RACK_ENV`, or defaults to `development`).
362
-
363
- > [!NOTE]
364
- > Under `test`, the effective default model is `claude-3-haiku-20240307` — a full
365
- > dated model id. Short aliases like `claude-haiku-3-5` are **not** valid RubyLLM
366
- > model ids and raise `RubyLLM::ModelNotFoundError` at robot construction.
367
-
368
- ## Rails Integration
369
-
370
- > [!NOTE]
371
- > Core RobotLab ships **no Railtie and no Engine**. It performs two bare
372
- > `defined?(::Rails)` checks: the default logger becomes `Rails.logger`, and
373
- > `template_path` resolves to `Rails.root/app/prompts` when left unset. Generators,
374
- > `RobotLab::Job`, and Turbo broadcasting live in the separate
375
- > [robot_lab-rails](https://github.com/MadBomber/robot_lab-rails) gem.
376
-
377
- > [!WARNING]
378
- > **Under Rails, `./config/robot_lab.yml` must be environment-sectioned — a flat
379
- > file is ignored.** Rails' anyway_config integration sets
380
- > `Anyway::Settings.current_environment` to `Rails.env`, which switches the project
381
- > config loader into environmental mode. Keys then have to live under
382
- > `development:` / `test:` / `production:`; anything written at the root of the file
383
- > is dropped. Outside Rails the rule is exactly inverted — flat keys are read and an
384
- > environment section is ignored.
385
-
386
- ```yaml title="config/robot_lab.yml (under Rails)"
387
- development:
388
- ruby_llm:
389
- anthropic_api_key: <%= Rails.application.credentials.anthropic_api_key %>
390
- model: claude-sonnet-4
391
- request_timeout: 180
392
- max_retries: 5
393
- template_path: null # auto-detects app/prompts in Rails
394
-
395
- production:
396
- ruby_llm:
397
- anthropic_api_key: <%= Rails.application.credentials.anthropic_api_key %>
398
- model: claude-sonnet-4
399
- request_timeout: 180
400
- max_retries: 5
401
- ```
402
-
403
- The same file outside Rails would instead be written flat:
404
-
405
- ```yaml title="config/robot_lab.yml (no Rails)"
406
- ruby_llm:
407
- model: claude-sonnet-4
408
- request_timeout: 180
409
-
410
- template_path: prompts
411
- ```
412
-
413
- You can also use Rails credentials:
414
-
415
- ```bash
416
- rails credentials:edit
417
- ```
418
-
419
- ```yaml
420
- # config/credentials.yml.enc
421
- anthropic_api_key: sk-ant-...
422
- openai_api_key: sk-...
423
- ```
424
-
425
- `./config/robot_lab.yml` is evaluated through ERB, so credentials can be
426
- referenced inline as shown above. Note that this only works in the **project**
427
- config file — the `~/.config/robot_lab/robot_lab.yml` user file is not run
428
- through ERB.
429
-
430
- ## RunConfig: Shared Operational Defaults
431
-
432
- `RunConfig` is a configuration object that lets you express operational defaults for LLM settings, tools, callbacks, and infrastructure. Unlike `RobotLab.config` (which is global and static), RunConfig flows through the hierarchy and can be customized at each level:
433
-
434
- ```
435
- RobotLab.config (global) -> Network RunConfig -> Robot RunConfig -> Template front matter -> Task RunConfig -> Runtime
436
- ```
437
-
438
- ### Creating a RunConfig
439
-
440
- ```ruby
441
- # Keyword construction
442
- config = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.7)
443
-
444
- # Block DSL
445
- config = RobotLab::RunConfig.new do |c|
446
- c.model "claude-sonnet-4"
447
- c.temperature 0.7
448
- c.max_tokens 2000
449
- end
450
-
451
- # Chaining
452
- config = RobotLab::RunConfig.new
453
- .model("claude-sonnet-4")
454
- .temperature(0.7)
455
- ```
456
-
457
- ### Applying RunConfig
458
-
459
- Pass `config:` to robots and networks. Explicit constructor kwargs always override the RunConfig:
460
-
461
- ```ruby
462
- # Shared config for a team of robots
463
- shared = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.5)
464
-
465
- # Robot uses shared config
466
- robot = RobotLab.build(
467
- name: "writer",
468
- system_prompt: "You are a creative writer.",
469
- config: shared,
470
- temperature: 0.9 # overrides shared config's 0.5
471
- )
472
-
473
- # Network-level config
474
- network = RobotLab.create_network(name: "pipeline", config: shared) do
475
- task :analyzer, analyzer_robot, depends_on: :none
476
- task :writer, writer_robot, depends_on: [:analyzer]
477
- end
478
- ```
479
-
480
- > [!WARNING]
481
- > **A network-level `config:` propagates only `mcp` and `tools`** — and only when
482
- > the member robot opts in by passing `mcp: :inherit` / `tools: :inherit` on its
483
- > `run`. LLM fields (`model`, `temperature`, `max_tokens`, …) and callbacks
484
- > (`on_content`, `on_tool_call`, `on_tool_result`) are read from each robot's
485
- > **own** config at construction time and are never inherited from the network.
486
- > The only field the network itself consumes is `max_concurrent_robots`.
487
- >
488
- > If you want a whole team on one model, pass the same `config:` to each robot:
489
- >
490
- > ```ruby
491
- > shared = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.5)
492
- > analyst = RobotLab.build(name: "analyst", system_prompt: "...", config: shared)
493
- > writer = RobotLab.build(name: "writer", system_prompt: "...", config: shared)
494
- > ```
495
- >
496
- > A per-task `config:` is merged into the network config and is subject to the
497
- > same `mcp`/`tools`-only limitation.
498
-
499
- ### Merging Configs
500
-
501
- RunConfig supports merge semantics where the more-specific config's values win:
502
-
503
- ```ruby
504
- network_config = RobotLab::RunConfig.new(model: "claude-sonnet-4", temperature: 0.5)
505
- robot_config = RobotLab::RunConfig.new(temperature: 0.9)
506
- effective = network_config.merge(robot_config)
507
- effective.model #=> "claude-sonnet-4" (inherited)
508
- effective.temperature #=> 0.9 (overridden)
509
- ```
510
-
511
- ### Available Fields
512
-
513
- | Category | Fields |
514
- |----------|--------|
515
- | **LLM** | `model`, `temperature`, `top_p`, `top_k`, `max_tokens`, `presence_penalty`, `frequency_penalty`, `stop` |
516
- | **Tools** | `mcp`, `tools` |
517
- | **Callbacks** | `on_tool_call`, `on_tool_result`, `on_content` |
518
- | **Infrastructure** | `bus`, `enable_cache`, `max_tool_rounds`, `token_budget`, `cost_budget`, `max_tools`, `ractor_pool_size`, `max_concurrent_robots`, `doom_loop_threshold`, `auto_compact`, `compact_threshold` |
519
-
520
- `cost_budget` mirrors `token_budget` for cumulative dollar spend — see [Budgets](../guides/observability.md#budgets-token-cost). `max_tools` overrides the default 128-tool ceiling enforced on every turn before tools are handed to the provider — see [Tool Capping](../guides/using-tools.md#tool-capping-and-per-turn-filtering).
521
-
522
- ### RunConfig vs RobotLab.config
523
-
524
- | | `RobotLab.config` | `RunConfig` |
525
- |---|---|---|
526
- | **Scope** | Global (all robots) | Per-network, per-robot, or per-task |
527
- | **Source** | YAML files, env vars | Code (constructor, block DSL) |
528
- | **Mutability** | Loaded once, rarely changed | Created per use case, merged |
529
- | **Purpose** | API keys, timeouts, defaults | Model, temperature, tools per workflow |
530
-
531
- ## Robot-Level Configuration
532
-
533
- Individual robots can override the global model and other settings:
534
-
535
- ```ruby
536
- # Override model for a specific robot
537
- robot = RobotLab.build(
538
- name: "fast_bot",
539
- system_prompt: "You are a quick responder.",
540
- model: "claude-3-haiku-20240307",
541
- temperature: 0.3,
542
- max_tokens: 500
543
- )
544
-
545
- # Or use chaining at runtime
546
- robot.with_temperature(0.9).with_params(max_tokens: 2000).run("Tell me a story.")
547
- ```
548
-
549
- > [!WARNING]
550
- > There is **no `with_max_tokens`, `with_top_p`, `with_top_k`, `with_stop`,
551
- > `with_presence_penalty`, or `with_frequency_penalty`** — calling them raises
552
- > `NoMethodError`. The complete chainable set is `with_context`, `with_headers`,
553
- > `with_instructions`, `with_model`, `with_params`, `with_schema`,
554
- > `with_temperature`, `with_thinking`, `with_tool`, `with_tools`, plus RobotLab's
555
- > own `with_template` and `with_bus`. For everything else use a constructor
556
- > keyword argument or `with_params(...)`.
557
-
558
- ## Hierarchical MCP and Tools
559
-
560
- MCP servers and tools use a hierarchical configuration: `runtime > robot > network > global`. Each level can specify:
561
-
562
- - `:inherit` -- Use the parent level's configuration
563
- - `:none` -- No MCP servers or tools at this level
564
- - An explicit array -- A name **allowlist** (not a local-vs-MCP switch). Entries are
565
- compared as strings against each attached tool's `name`, so they must match the
566
- form the tool was attached in: a tool attached as a class matches `[RefundTool]`
567
- or `%w[RefundTool]`, while one attached as an instance matches `%w[refund]`
568
-
569
- > [!WARNING]
570
- > **`tools:` and `mcp:` both default to `:none` — including on `run()` itself.**
571
- > `Robot#run` is declared `run(message = nil, ..., mcp: :none, tools: :none, ...)`,
572
- > and an explicit `:none` means "send zero tools this turn". So a plain
573
- > `robot.run("...")` sends the LLM **no tools and connects no MCP servers**, even
574
- > when you passed `local_tools:` or `mcp:` at build time.
575
- >
576
- > The fix goes on the **run**, not the build:
577
- >
578
- > ```ruby
579
- > robot.run("...", tools: :inherit) # send the attached local tools
580
- > robot.run("...", mcp: :inherit, tools: :inherit) # connect MCP and send its tools
581
- > ```
582
- >
583
- > `mcp: :inherit` triggers the connection; `tools: :inherit` is additionally
584
- > required for the MCP tools to actually be handed to the model.
585
-
586
- > [!IMPORTANT]
587
- > **For a standalone robot, do not pass `tools: :inherit` at build time.** Build-time
588
- > `:inherit` resolves against the parent level, and for a standalone robot the parent
589
- > is the global `:none` — producing an allowlist of `["none"]` that matches nothing
590
- > and suppresses the tools even when the run asks for `:inherit`. Verified
591
- > resolution for a standalone robot:
592
- >
593
- > | build `tools:` | run `tools:` | tools sent |
594
- > |---|---|---|
595
- > | unset | `:none` (default) | none |
596
- > | unset | `:inherit` | the attached tools ✅ |
597
- > | `:inherit` | `:inherit` | **none** ❌ |
598
- > | `:inherit` | `:none` | none |
599
- > | `:none` | `:inherit` | the attached tools ✅ |
600
- >
601
- > Leave `tools:` unset at build time — unless the robot is a member of a network.
602
-
603
- > [!NOTE]
604
- > **Inside a network, build-time `:inherit` is the opt-in, not a bug.** The parent
605
- > is resolved at run time as the network's `config:`, so `:inherit` is how a robot
606
- > asks for the network-level allowlist. With
607
- > `RobotLab::RunConfig.new(tools: %w[RefundTool])` on the network and a robot
608
- > holding `local_tools: [RefundTool, InvoiceTool]`:
609
- >
610
- > | build `tools:` | task `tools:` | tools sent |
611
- > |---|---|---|
612
- > | unset | omitted (`:none`) | none |
613
- > | unset | `:inherit` | `refund`, `invoice` — the network allowlist is **not** applied |
614
- > | `:inherit` | `:inherit` | `refund` — the network allowlist **is** applied ✅ |
615
- > | `:inherit` | omitted (`:none`) | none |
616
- >
617
- > The same reasoning applies to `mcp:`.
618
-
619
- ```ruby
620
- # Correct: attach tools at build time, request them at run time
621
- robot = RobotLab.build(
622
- name: "calculator",
623
- system_prompt: "You solve math problems.",
624
- local_tools: [Calculator]
625
- )
626
-
627
- robot.run("What is 17 * 23?", tools: :inherit)
628
-
629
- # Robot with MCP servers attached at build time
630
- robot = RobotLab.build(
631
- name: "agent",
632
- system_prompt: "You are helpful.",
633
- mcp: [{ name: "filesystem", transport: { type: "stdio", command: "mcp-server-filesystem" } }]
634
- )
635
-
636
- robot.run("List the files in ./lib", mcp: :inherit, tools: :inherit)
637
- ```
638
-
639
- See [Runtime Tool Filtering](../guides/using-tools.md#runtime-tool-filtering) for the full `:inherit`/`:none`/array semantics.
640
-
641
- ## Next Steps
642
-
643
- - [Building Robots](../guides/building-robots.md) - Create custom robots
644
- - [Creating Networks](../guides/creating-networks.md) - Network configuration
645
- - [MCP Integration](../guides/mcp-integration.md) - Configure MCP servers
@@ -1,56 +0,0 @@
1
- # Getting Started
2
-
3
- Welcome to RobotLab! This section will help you get up and running quickly.
4
-
5
- ## What You'll Learn
6
-
7
- In this section, you'll learn how to:
8
-
9
- 1. **Install RobotLab** - Add the gem to your project
10
- 2. **Configure Your Environment** - Set up API keys and defaults
11
- 3. **Create Your First Robot** - Build a simple AI assistant
12
- 4. **Run a Network** - Execute a multi-robot workflow
13
-
14
- ## Prerequisites
15
-
16
- Before you begin, make sure you have:
17
-
18
- - **Ruby 3.2+** installed
19
- - An **API key** from at least one LLM provider:
20
- - [Anthropic](https://console.anthropic.com/) (recommended)
21
- - [OpenAI](https://platform.openai.com/)
22
- - [Google AI](https://ai.google.dev/)
23
-
24
- ## Quick Links
25
-
26
- <div class="grid cards" markdown>
27
-
28
- - [:octicons-download-24: **Installation**](installation.md)
29
-
30
- Install RobotLab and dependencies
31
-
32
- - [:octicons-rocket-24: **Quick Start**](quick-start.md)
33
-
34
- Build your first robot in 5 minutes
35
-
36
- - [:octicons-gear-24: **Configuration**](configuration.md)
37
-
38
- Configure API keys and defaults
39
-
40
- </div>
41
-
42
- ## Estimated Time
43
-
44
- | Guide | Time |
45
- |-------|------|
46
- | Installation | 2 minutes |
47
- | Quick Start | 5 minutes |
48
- | Configuration | 5 minutes |
49
-
50
- ## Need Help?
51
-
52
- If you run into issues:
53
-
54
- - Check the [API Reference](../api/index.md) for detailed documentation
55
- - Browse [Examples](../examples/index.md) for working code
56
- - Open an issue on [GitHub](https://github.com/madbomber/robot_lab/issues)