prompt_objects 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -0
  3. data/README.md +93 -22
  4. data/exe/poop +5 -0
  5. data/exe/prompt_objects +1 -1108
  6. data/exe/prompt_objects_mcp +5 -3
  7. data/lib/prompt_objects/capability.rb +33 -0
  8. data/lib/prompt_objects/cli/diagnostics_command.rb +69 -0
  9. data/lib/prompt_objects/cli/env_command.rb +435 -0
  10. data/lib/prompt_objects/cli/events_command.rb +145 -0
  11. data/lib/prompt_objects/cli/explore_command.rb +155 -0
  12. data/lib/prompt_objects/cli/helpers.rb +91 -0
  13. data/lib/prompt_objects/cli/message_command.rb +216 -0
  14. data/lib/prompt_objects/cli/repl_command.rb +366 -0
  15. data/lib/prompt_objects/cli/serve_command.rb +162 -0
  16. data/lib/prompt_objects/cli.rb +64 -422
  17. data/lib/prompt_objects/connectors/base.rb +16 -29
  18. data/lib/prompt_objects/connectors/mcp.rb +82 -98
  19. data/lib/prompt_objects/domain/records.rb +45 -0
  20. data/lib/prompt_objects/environment/exporter.rb +5 -4
  21. data/lib/prompt_objects/environment/git.rb +21 -1
  22. data/lib/prompt_objects/environment/importer.rb +5 -4
  23. data/lib/prompt_objects/environment/manager.rb +44 -6
  24. data/lib/prompt_objects/environment/manifest.rb +26 -4
  25. data/lib/prompt_objects/environment.rb +1337 -20
  26. data/lib/prompt_objects/execution/blocking_executor.rb +88 -0
  27. data/lib/prompt_objects/execution/context.rb +137 -0
  28. data/lib/prompt_objects/execution/contracts.rb +59 -0
  29. data/lib/prompt_objects/execution/permit_pool.rb +49 -0
  30. data/lib/prompt_objects/execution/policy.rb +47 -0
  31. data/lib/prompt_objects/execution/resource_lock_manager.rb +63 -0
  32. data/lib/prompt_objects/execution/runner.rb +498 -0
  33. data/lib/prompt_objects/execution/scheduler.rb +325 -0
  34. data/lib/prompt_objects/llm/factory.rb +4 -4
  35. data/lib/prompt_objects/llm/gemini_adapter.rb +25 -8
  36. data/lib/prompt_objects/llm/openai_adapter.rb +9 -1
  37. data/lib/prompt_objects/llm/pricing.rb +9 -2
  38. data/lib/prompt_objects/llm/response.rb +9 -4
  39. data/lib/prompt_objects/loader.rb +28 -1
  40. data/lib/prompt_objects/mcp/server.rb +6 -3
  41. data/lib/prompt_objects/mcp/tools/get_conversation.rb +15 -11
  42. data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +2 -2
  43. data/lib/prompt_objects/mcp/tools/respond_to_request.rb +3 -3
  44. data/lib/prompt_objects/mcp/tools/send_message.rb +42 -32
  45. data/lib/prompt_objects/operations/diagnostics.rb +115 -0
  46. data/lib/prompt_objects/operations/retention.rb +75 -0
  47. data/lib/prompt_objects/operations/run_trace_builder.rb +152 -0
  48. data/lib/prompt_objects/primitives/http_get.rb +2 -0
  49. data/lib/prompt_objects/primitives/list_files.rb +2 -0
  50. data/lib/prompt_objects/primitives/read_file.rb +2 -0
  51. data/lib/prompt_objects/primitives/think.rb +36 -0
  52. data/lib/prompt_objects/primitives/write_file.rb +9 -0
  53. data/lib/prompt_objects/prompt_object.rb +171 -519
  54. data/lib/prompt_objects/repositories/artifact_repository.rb +109 -0
  55. data/lib/prompt_objects/repositories/base_repository.rb +37 -0
  56. data/lib/prompt_objects/repositories/definition_repository.rb +36 -0
  57. data/lib/prompt_objects/repositories/env_data_repository.rb +103 -0
  58. data/lib/prompt_objects/repositories/event_repository.rb +105 -0
  59. data/lib/prompt_objects/repositories/message_repository.rb +73 -0
  60. data/lib/prompt_objects/repositories/run_repository.rb +254 -0
  61. data/lib/prompt_objects/repositories/thread_repository.rb +87 -0
  62. data/lib/prompt_objects/repositories/tool_execution_repository.rb +88 -0
  63. data/lib/prompt_objects/repositories/workspace_session_repository.rb +61 -0
  64. data/lib/prompt_objects/server/api/routes.rb +549 -53
  65. data/lib/prompt_objects/server/app.rb +133 -14
  66. data/lib/prompt_objects/server/file_watcher.rb +9 -0
  67. data/lib/prompt_objects/server/public/assets/index-BjKlODDD.js +90 -0
  68. data/lib/prompt_objects/server/public/assets/index-w3fpIb5c.css +1 -0
  69. data/lib/prompt_objects/server/public/index.html +2 -2
  70. data/lib/prompt_objects/server/websocket_handler.rb +202 -227
  71. data/lib/prompt_objects/server.rb +170 -1
  72. data/lib/prompt_objects/service.rb +129 -0
  73. data/lib/prompt_objects/session/store.rb +600 -13
  74. data/lib/prompt_objects/universal/add_capability.rb +1 -1
  75. data/lib/prompt_objects/universal/create_capability.rb +4 -2
  76. data/lib/prompt_objects/universal/delete_env_data.rb +23 -15
  77. data/lib/prompt_objects/universal/delete_primitive.rb +1 -1
  78. data/lib/prompt_objects/universal/dispatch_po.rb +54 -0
  79. data/lib/prompt_objects/universal/get_env_data.rb +8 -14
  80. data/lib/prompt_objects/universal/get_run_status.rb +30 -0
  81. data/lib/prompt_objects/universal/join_runs.rb +35 -0
  82. data/lib/prompt_objects/universal/list_env_data.rb +10 -14
  83. data/lib/prompt_objects/universal/modify_primitive.rb +1 -1
  84. data/lib/prompt_objects/universal/render_artifact.rb +91 -0
  85. data/lib/prompt_objects/universal/request_primitive.rb +1 -1
  86. data/lib/prompt_objects/universal/{store_env_data.rb → set_env_data.rb} +34 -20
  87. data/lib/prompt_objects/version.rb +5 -0
  88. data/lib/prompt_objects.rb +33 -8
  89. data/objects/coordinator.md +8 -4
  90. data/templates/arc-agi-1/objects/data_manager.md +2 -2
  91. data/templates/arc-agi-1/objects/observer.md +2 -2
  92. data/templates/arc-agi-1/objects/solver.md +6 -5
  93. data/templates/arc-agi-1/objects/verifier.md +2 -2
  94. data/templates/arc-agi-3/manifest.yml +19 -0
  95. data/templates/arc-agi-3/objects/analyst.md +79 -0
  96. data/templates/arc-agi-3/objects/player.md +76 -0
  97. data/templates/arc-agi-3/objects/strategist.md +97 -0
  98. data/templates/arc-agi-3/primitives/action_log.rb +133 -0
  99. data/templates/arc-agi-3/primitives/arc3_api.rb +223 -0
  100. data/templates/arc-agi-3/primitives/arc3_scorecard.rb +131 -0
  101. data/templates/arc-agi-3/primitives/frame_diff.rb +143 -0
  102. data/templates/arc-agi-3/primitives/frame_info.rb +96 -0
  103. data/templates/arc-agi-3/primitives/render_frame.rb +140 -0
  104. data/templates/basic/objects/basic.md +11 -3
  105. data/templates/chiptune/extras/sonic_pi_boot.rb +220 -0
  106. data/templates/chiptune/manifest.yml +20 -0
  107. data/templates/chiptune/objects/conductor.md +184 -0
  108. data/templates/chiptune/objects/sonic_pi.md +65 -0
  109. data/templates/chiptune/objects/voice_bass.md +44 -0
  110. data/templates/chiptune/objects/voice_lead.md +44 -0
  111. data/templates/chiptune/objects/voice_pad.md +43 -0
  112. data/templates/chiptune/objects/voice_perc.md +45 -0
  113. data/templates/chiptune/primitives/play_note.rb +59 -0
  114. data/templates/chiptune/primitives/play_sequence.rb +55 -0
  115. data/templates/chiptune/primitives/query_sonic_pi.rb +141 -0
  116. data/templates/chiptune/primitives/set_synth.rb +57 -0
  117. data/templates/chiptune/primitives/set_tempo.rb +45 -0
  118. data/templates/chiptune/primitives/stop_voice.rb +46 -0
  119. data/templates/chiptune/primitives/support/osc_bridge.rb +33 -0
  120. data/templates/chiptune/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  121. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  122. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  123. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  124. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  125. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  126. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  127. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  128. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  129. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  130. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  131. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  132. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  133. data/templates/chiptune/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  134. data/templates/developer/objects/code_reviewer.md +1 -1
  135. data/templates/developer/objects/coordinator.md +16 -3
  136. data/templates/developer/objects/debugger.md +3 -3
  137. data/templates/empty/objects/assistant.md +10 -5
  138. data/templates/minimal/objects/assistant.md +10 -5
  139. data/templates/music/extras/sonic_pi_boot.rb +220 -0
  140. data/templates/music/manifest.yml +16 -0
  141. data/templates/music/objects/conductor.md +154 -0
  142. data/templates/music/objects/sonic_pi.md +65 -0
  143. data/templates/music/primitives/play_note.rb +55 -0
  144. data/templates/music/primitives/play_sequence.rb +51 -0
  145. data/templates/music/primitives/query_sonic_pi.rb +139 -0
  146. data/templates/music/primitives/set_synth.rb +53 -0
  147. data/templates/music/primitives/set_tempo.rb +43 -0
  148. data/templates/music/primitives/stop_voice.rb +44 -0
  149. data/templates/music/primitives/support/osc_bridge.rb +33 -0
  150. data/templates/music/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  151. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  152. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  153. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  154. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  155. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  156. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  157. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  158. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  159. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  160. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  161. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  162. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  163. data/templates/music/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  164. data/templates/music-beginner/README.md +100 -0
  165. data/templates/music-beginner/extras/README.md +27 -0
  166. data/templates/music-beginner/extras/sonic_pi_boot.rb +297 -0
  167. data/templates/music-beginner/manifest.yml +25 -0
  168. data/templates/music-beginner/objects/conductor.md +222 -0
  169. data/templates/music-beginner/objects/engine_setup.md +54 -0
  170. data/templates/music-beginner/objects/voice_bass.md +43 -0
  171. data/templates/music-beginner/objects/voice_keys.md +48 -0
  172. data/templates/music-beginner/objects/voice_pad.md +46 -0
  173. data/templates/music-beginner/objects/voice_percussion.md +45 -0
  174. data/templates/music-beginner/objects/voice_texture.md +37 -0
  175. data/templates/music-beginner/primitives/play_pattern.rb +118 -0
  176. data/templates/music-beginner/primitives/query_music_engine.rb +94 -0
  177. data/templates/music-beginner/primitives/set_instrument.rb +47 -0
  178. data/templates/music-beginner/primitives/set_tempo.rb +43 -0
  179. data/templates/music-beginner/primitives/set_voice_level.rb +46 -0
  180. data/templates/music-beginner/primitives/stop_voice.rb +37 -0
  181. data/templates/music-beginner/primitives/support/osc_bridge.rb +25 -0
  182. data/templates/music-beginner/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  183. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  184. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  185. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  186. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  187. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  188. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  189. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  190. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  191. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  192. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  193. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  194. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  195. data/templates/music-beginner/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  196. data/templates/music-pro/extras/AUDITION.md +100 -0
  197. data/templates/music-pro/extras/sonic_pi_boot.rb +546 -0
  198. data/templates/music-pro/manifest.yml +19 -0
  199. data/templates/music-pro/objects/conductor.md +126 -0
  200. data/templates/music-pro/objects/sonic_pi.md +35 -0
  201. data/templates/music-pro/objects/voice_harmony.md +48 -0
  202. data/templates/music-pro/objects/voice_rhythm.md +43 -0
  203. data/templates/music-pro/objects/voice_texture.md +42 -0
  204. data/templates/music-pro/primitives/define_patch.rb +46 -0
  205. data/templates/music-pro/primitives/query_music_engine.rb +69 -0
  206. data/templates/music-pro/primitives/set_live_pattern.rb +70 -0
  207. data/templates/music-pro/primitives/set_tempo.rb +31 -0
  208. data/templates/music-pro/primitives/stop_voice.rb +31 -0
  209. data/templates/music-pro/primitives/support/music_protocol.rb +136 -0
  210. data/templates/music-pro/primitives/support/osc_bridge.rb +33 -0
  211. data/templates/music-pro/primitives/trigger_event.rb +44 -0
  212. data/templates/music-pro/vendor/osc-ruby-1.1.5/LICENSE +19 -0
  213. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/address_pattern.rb +58 -0
  214. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/broadcast_client.rb +24 -0
  215. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/bundle.rb +46 -0
  216. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/client.rb +13 -0
  217. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/core_ext/time.rb +6 -0
  218. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/em_server.rb +63 -0
  219. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/message.rb +46 -0
  220. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/network_packet.rb +42 -0
  221. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_argument.rb +26 -0
  222. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_packet.rb +140 -0
  223. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/osc_types.rb +53 -0
  224. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby/server.rb +91 -0
  225. data/templates/music-pro/vendor/osc-ruby-1.1.5/lib/osc-ruby.rb +18 -0
  226. data/templates/writer/objects/coordinator.md +14 -3
  227. data/templates/writer/objects/editor.md +1 -1
  228. data/templates/writer/objects/researcher.md +2 -2
  229. data/tools/thread-explorer.html +1 -1
  230. metadata +172 -65
  231. data/CLAUDE.md +0 -177
  232. data/Gemfile +0 -10
  233. data/Rakefile +0 -27
  234. data/frontend/.gitignore +0 -3
  235. data/frontend/index.html +0 -17
  236. data/frontend/package-lock.json +0 -4540
  237. data/frontend/package.json +0 -36
  238. data/frontend/postcss.config.js +0 -6
  239. data/frontend/src/App.tsx +0 -104
  240. data/frontend/src/canvas/CanvasView.tsx +0 -113
  241. data/frontend/src/canvas/ForceLayout.ts +0 -115
  242. data/frontend/src/canvas/SceneManager.ts +0 -587
  243. data/frontend/src/canvas/canvasStore.ts +0 -47
  244. data/frontend/src/canvas/constants.ts +0 -95
  245. data/frontend/src/canvas/controls/CameraControls.ts +0 -98
  246. data/frontend/src/canvas/edges/MessageArc.ts +0 -149
  247. data/frontend/src/canvas/inspector/InspectorPanel.tsx +0 -31
  248. data/frontend/src/canvas/inspector/POInspector.tsx +0 -262
  249. data/frontend/src/canvas/inspector/ToolCallInspector.tsx +0 -67
  250. data/frontend/src/canvas/nodes/PONode.ts +0 -249
  251. data/frontend/src/canvas/nodes/ToolCallNode.ts +0 -116
  252. data/frontend/src/canvas/types.ts +0 -24
  253. data/frontend/src/components/ContextMenu.tsx +0 -68
  254. data/frontend/src/components/EnvDataPane.tsx +0 -69
  255. data/frontend/src/components/Inspector.tsx +0 -263
  256. data/frontend/src/components/MarkdownMessage.tsx +0 -155
  257. data/frontend/src/components/MethodList.tsx +0 -90
  258. data/frontend/src/components/ModelSelector.tsx +0 -115
  259. data/frontend/src/components/NotificationPanel.tsx +0 -130
  260. data/frontend/src/components/ObjectList.tsx +0 -78
  261. data/frontend/src/components/PaneSlot.tsx +0 -30
  262. data/frontend/src/components/SourcePane.tsx +0 -202
  263. data/frontend/src/components/SystemBar.tsx +0 -74
  264. data/frontend/src/components/Transcript.tsx +0 -76
  265. data/frontend/src/components/UsagePanel.tsx +0 -105
  266. data/frontend/src/components/Workspace.tsx +0 -260
  267. data/frontend/src/components/index.ts +0 -12
  268. data/frontend/src/hooks/useResize.ts +0 -55
  269. data/frontend/src/hooks/useWebSocket.ts +0 -559
  270. data/frontend/src/index.css +0 -102
  271. data/frontend/src/main.tsx +0 -10
  272. data/frontend/src/store/index.ts +0 -311
  273. data/frontend/src/types/index.ts +0 -176
  274. data/frontend/tailwind.config.js +0 -44
  275. data/frontend/tsconfig.json +0 -30
  276. data/frontend/vite.config.ts +0 -29
  277. data/lib/prompt_objects/server/public/assets/index-DEPawnfZ.js +0 -4345
  278. data/lib/prompt_objects/server/public/assets/index-oMrRce1m.css +0 -1
  279. data/lib/prompt_objects/universal/add_primitive.rb +0 -118
  280. data/lib/prompt_objects/universal/ask_human.rb +0 -109
  281. data/lib/prompt_objects/universal/create_primitive.rb +0 -174
  282. data/lib/prompt_objects/universal/list_primitives.rb +0 -145
  283. data/lib/prompt_objects/universal/think.rb +0 -41
  284. data/lib/prompt_objects/universal/update_env_data.rb +0 -88
  285. data/prompt_objects.gemspec +0 -50
  286. data/templates/basic/.gitignore +0 -2
  287. data/templates/developer/.gitignore +0 -5
  288. data/templates/empty/.gitignore +0 -5
  289. data/templates/empty/objects/.gitkeep +0 -0
  290. data/templates/minimal/.gitignore +0 -5
  291. data/templates/writer/.gitignore +0 -5
@@ -10,7 +10,7 @@ module PromptObjects
10
10
  end
11
11
 
12
12
  def description
13
- "Add a capability to a prompt object, allowing it to use new tools. Can target self or another PO."
13
+ "Add an existing capability (a primitive tool or another prompt object) to a prompt object, allowing it to use that capability. Can target self or another PO. Use list_capabilities to discover what's available."
14
14
  end
15
15
 
16
16
  def parameters
@@ -13,7 +13,9 @@ module PromptObjects
13
13
  end
14
14
 
15
15
  def description
16
- "Create a new capability. Use type='prompt_object' for LLM-backed specialists, or type='primitive' for deterministic Ruby tools."
16
+ "Create a new capability. Use type='prompt_object' for LLM-backed specialists, or type='primitive' for deterministic Ruby tools. " \
17
+ "For prompt objects, capabilities are the exact callable tools/delegates the new object receives; an informational delegate " \
18
+ "does not grant access to that delegate's tools."
17
19
  end
18
20
 
19
21
  def parameters
@@ -37,7 +39,7 @@ module PromptObjects
37
39
  capabilities: {
38
40
  type: "array",
39
41
  items: { type: "string" },
40
- description: "(prompt_object only) List of capabilities this PO can use"
42
+ description: "(prompt_object only) Exact tools and delegates this PO may call. Grant direct action tools for every action it must perform; do not use a related PO as a proxy for tools it does not expose."
41
43
  },
42
44
  identity: {
43
45
  type: "string",
@@ -4,6 +4,15 @@ module PromptObjects
4
4
  module Universal
5
5
  # Universal capability to delete a key from the shared environment data.
6
6
  class DeleteEnvData < Primitive
7
+ execution_policy(
8
+ parallel_safe: true,
9
+ side_effect: :write,
10
+ resource_keys: ->(arguments, context, _capability) {
11
+ key = arguments[:key] || arguments["key"]
12
+ ["workspace:#{context.workspace_session_id}:env_data:#{key}"]
13
+ }
14
+ )
15
+
7
16
  def name
8
17
  "delete_env_data"
9
18
  end
@@ -29,13 +38,17 @@ module PromptObjects
29
38
  key = message[:key] || message["key"]
30
39
  return "Error: 'key' is required" unless key
31
40
 
32
- root_thread_id = resolve_root_thread(context)
41
+ root_thread_id = context.env_data_scope
33
42
  return "Error: Could not resolve thread scope (no active session)" unless root_thread_id
34
43
 
35
44
  store = context.env.session_store
36
45
  return "Error: Session store not available" unless store
37
46
 
38
- deleted = store.delete_env_data(root_thread_id: root_thread_id, key: key)
47
+ deleted = if context.env.respond_to?(:delete_environment_data)
48
+ context.env.delete_environment_data(key: key, context: context)
49
+ else
50
+ store.delete_env_data(root_thread_id: root_thread_id, key: key)
51
+ end
39
52
 
40
53
  unless deleted
41
54
  return "Key '#{key}' not found in environment data."
@@ -49,22 +62,17 @@ module PromptObjects
49
62
  message: { action: "delete", key: key }
50
63
  )
51
64
 
52
- context.env.notify_env_data_changed(action: "delete", root_thread_id: root_thread_id, key: key, stored_by: stored_by)
65
+ unless context.env.respond_to?(:delete_environment_data)
66
+ context.env.notify_env_data_changed(
67
+ action: "delete",
68
+ root_thread_id: root_thread_id,
69
+ key: key,
70
+ stored_by: stored_by
71
+ )
72
+ end
53
73
 
54
74
  "Deleted '#{key}' from environment data."
55
75
  end
56
-
57
- private
58
-
59
- def resolve_root_thread(context)
60
- store = context.env.session_store
61
- return nil unless store
62
-
63
- po = context.env.registry.get(context.calling_po)
64
- return nil unless po&.respond_to?(:session_id) && po.session_id
65
-
66
- store.resolve_root_thread(po.session_id)
67
- end
68
76
  end
69
77
  end
70
78
  end
@@ -7,7 +7,7 @@ module PromptObjects
7
7
  # USE WITH CAUTION - this permanently deletes the primitive file.
8
8
  class DeletePrimitive < Primitive
9
9
  # Built-in primitives that cannot be deleted
10
- PROTECTED_PRIMITIVES = %w[read_file list_files write_file http_get].freeze
10
+ PROTECTED_PRIMITIVES = %w[read_file list_files write_file http_get think].freeze
11
11
 
12
12
  def name
13
13
  "delete_primitive"
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptObjects
4
+ module Universal
5
+ # Enqueue independent PO work and return its durable identity immediately.
6
+ class DispatchPO < Primitive
7
+ execution_policy parallel_safe: true, side_effect: :write, resource_keys: ->(_arguments, _context, _capability) { [] }
8
+
9
+ def name = "dispatch_po"
10
+
11
+ def description
12
+ "Dispatch work to an allowed Prompt Object without waiting for its response. " \
13
+ "Returns run_id and thread_id; use get_run_status or join_runs when the result is needed later."
14
+ end
15
+
16
+ def parameters
17
+ {
18
+ type: "object",
19
+ properties: {
20
+ target_po: { type: "string", description: "Prompt Object listed in your capabilities" },
21
+ message: { type: "string", description: "Work to enqueue" },
22
+ thread_id: { type: "string", description: "Optional existing target thread" },
23
+ lifetime: {
24
+ type: "string", enum: %w[attached detached],
25
+ description: "attached cancels with the parent; detached may finish independently"
26
+ },
27
+ on_complete: {
28
+ type: "string",
29
+ description: "Optional follow-up instruction enqueued on your thread when the child finishes"
30
+ }
31
+ },
32
+ required: %w[target_po message]
33
+ }
34
+ end
35
+
36
+ def receive(message, context:)
37
+ target = message[:target_po] || message["target_po"]
38
+ content = message[:message] || message["message"]
39
+ raise Error, "target_po is required" if target.to_s.empty?
40
+ raise Error, "message is required" if content.to_s.empty?
41
+
42
+ result = context.env.dispatch_run(
43
+ target_po: target,
44
+ content: content,
45
+ context: context,
46
+ thread_id: message[:thread_id] || message["thread_id"],
47
+ lifetime: message[:lifetime] || message["lifetime"] || "attached",
48
+ on_complete: message[:on_complete] || message["on_complete"]
49
+ )
50
+ JSON.generate(result)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -4,6 +4,8 @@ module PromptObjects
4
4
  module Universal
5
5
  # Universal capability to retrieve shared data by key from the current delegation chain.
6
6
  class GetEnvData < Primitive
7
+ execution_policy parallel_safe: true, side_effect: :read
8
+
7
9
  def name
8
10
  "get_env_data"
9
11
  end
@@ -30,13 +32,17 @@ module PromptObjects
30
32
  key = message[:key] || message["key"]
31
33
  return "Error: 'key' is required" unless key
32
34
 
33
- root_thread_id = resolve_root_thread(context)
35
+ root_thread_id = context.env_data_scope
34
36
  return "Error: Could not resolve thread scope (no active session)" unless root_thread_id
35
37
 
36
38
  store = context.env.session_store
37
39
  return "Error: Session store not available" unless store
38
40
 
39
- entry = store.get_env_data(root_thread_id: root_thread_id, key: key)
41
+ entry = if context.env.respond_to?(:get_environment_data)
42
+ context.env.get_environment_data(key: key, context: context)
43
+ else
44
+ store.get_env_data(root_thread_id: root_thread_id, key: key)
45
+ end
40
46
  return "Key '#{key}' not found in environment data." unless entry
41
47
 
42
48
  context.bus.publish(
@@ -47,18 +53,6 @@ module PromptObjects
47
53
 
48
54
  JSON.generate(entry[:value])
49
55
  end
50
-
51
- private
52
-
53
- def resolve_root_thread(context)
54
- store = context.env.session_store
55
- return nil unless store
56
-
57
- po = context.env.registry.get(context.calling_po)
58
- return nil unless po&.respond_to?(:session_id) && po.session_id
59
-
60
- store.resolve_root_thread(po.session_id)
61
- end
62
56
  end
63
57
  end
64
58
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptObjects
4
+ module Universal
5
+ class GetRunStatus < Primitive
6
+ execution_policy parallel_safe: true, side_effect: :read
7
+
8
+ def name = "get_run_status"
9
+
10
+ def description
11
+ "Get the current durable status and result fields for a related dispatched run."
12
+ end
13
+
14
+ def parameters
15
+ {
16
+ type: "object",
17
+ properties: { run_id: { type: "string" } },
18
+ required: ["run_id"]
19
+ }
20
+ end
21
+
22
+ def receive(message, context:)
23
+ run_id = message[:run_id] || message["run_id"]
24
+ raise Error, "run_id is required" if run_id.to_s.empty?
25
+
26
+ JSON.generate(context.env.run_status(run_id, context: context))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptObjects
4
+ module Universal
5
+ class JoinRuns < Primitive
6
+ execution_policy parallel_safe: true, side_effect: :read
7
+
8
+ def name = "join_runs"
9
+
10
+ def description
11
+ "Wait for one or more related dispatched runs and return their terminal statuses/results in input order."
12
+ end
13
+
14
+ def parameters
15
+ {
16
+ type: "object",
17
+ properties: {
18
+ run_ids: { type: "array", items: { type: "string" } },
19
+ timeout: { type: "number", description: "Optional timeout in seconds" }
20
+ },
21
+ required: ["run_ids"]
22
+ }
23
+ end
24
+
25
+ def receive(message, context:)
26
+ run_ids = message[:run_ids] || message["run_ids"]
27
+ raise Error, "run_ids must not be empty" unless run_ids.is_a?(Array) && run_ids.any?
28
+
29
+ timeout = message[:timeout] || message["timeout"]
30
+ timeout = [[timeout.to_f, 0.1].max, 300].min if timeout
31
+ JSON.generate(context.env.join_runs(run_ids, context: context, timeout: timeout))
32
+ end
33
+ end
34
+ end
35
+ end
@@ -5,6 +5,8 @@ module PromptObjects
5
5
  # Universal capability to list all shared environment data keys and descriptions.
6
6
  # Returns a lightweight manifest without loading full values.
7
7
  class ListEnvData < Primitive
8
+ execution_policy parallel_safe: true, side_effect: :read
9
+
8
10
  def name
9
11
  "list_env_data"
10
12
  end
@@ -24,13 +26,19 @@ module PromptObjects
24
26
  end
25
27
 
26
28
  def receive(message, context:)
27
- root_thread_id = resolve_root_thread(context)
29
+ root_thread_id = context.env_data_scope
28
30
  return "Error: Could not resolve thread scope (no active session)" unless root_thread_id
29
31
 
30
32
  store = context.env.session_store
31
33
  return "Error: Session store not available" unless store
32
34
 
33
- entries = store.list_env_data(root_thread_id: root_thread_id)
35
+ entries = if context.env.respond_to?(:list_environment_data)
36
+ context.env.list_environment_data(context: context).map do |entry|
37
+ { key: entry[:key], short_description: entry[:short_description] }
38
+ end
39
+ else
40
+ store.list_env_data(root_thread_id: root_thread_id)
41
+ end
34
42
 
35
43
  if entries.empty?
36
44
  return "No environment data stored for this delegation chain."
@@ -44,18 +52,6 @@ module PromptObjects
44
52
 
45
53
  JSON.generate(entries)
46
54
  end
47
-
48
- private
49
-
50
- def resolve_root_thread(context)
51
- store = context.env.session_store
52
- return nil unless store
53
-
54
- po = context.env.registry.get(context.calling_po)
55
- return nil unless po&.respond_to?(:session_id) && po.session_id
56
-
57
- store.resolve_root_thread(po.session_id)
58
- end
59
55
  end
60
56
  end
61
57
  end
@@ -8,7 +8,7 @@ module PromptObjects
8
8
  # Allows POs to fix or improve their primitives.
9
9
  class ModifyPrimitive < Primitive
10
10
  # Stdlib primitives cannot be modified
11
- STDLIB_PRIMITIVES = %w[read_file list_files write_file http_get].freeze
11
+ STDLIB_PRIMITIVES = %w[read_file list_files write_file http_get think].freeze
12
12
 
13
13
  def name
14
14
  "modify_primitive"
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptObjects
4
+ module Universal
5
+ # Universal capability to render interactive HTML in the UI artifact panel.
6
+ # Artifacts are environment-wide — any PO can create or update any artifact.
7
+ #
8
+ # Modes:
9
+ # replace (default) — updates existing artifact with the same title in place
10
+ # version — always creates a new artifact entry
11
+ #
12
+ # The frontend renders artifacts in a sandboxed iframe with React 18,
13
+ # Tailwind CSS, and Babel (for JSX) available.
14
+ #
15
+ # Artifacts are bidirectional (BURP — Bidirectional UI Rendering Protocol):
16
+ # a PromptObjects.send(message) function is injected into every artifact.
17
+ # Calling it sends a natural-language message back to the PO that rendered
18
+ # the artifact (provenance "artifact:<title>"), so POs can build UIs the
19
+ # human interacts with instead of chatting.
20
+ class RenderArtifact < Primitive
21
+ execution_policy(
22
+ parallel_safe: true,
23
+ side_effect: :write,
24
+ resource_keys: ->(arguments, context, _capability) {
25
+ title = arguments[:title] || arguments["title"]
26
+ ["workspace:#{context.workspace_session_id}:artifact:#{title}"]
27
+ }
28
+ )
29
+
30
+ def name
31
+ "render_artifact"
32
+ end
33
+
34
+ def description
35
+ "Render an interactive HTML/JSX artifact in the UI panel. The sandboxed iframe ALREADY provides " \
36
+ "React 18, ReactDOM, Babel, and Tailwind, plus a <div id='root'> mount point. " \
37
+ "IMPORTANT: send ONLY your component markup — do NOT include <html>/<head>/<body> wrappers or your " \
38
+ "own <script src=...> CDN tags for React/Babel/Tailwind (the iframe provides them; your own copies " \
39
+ "conflict). Do NOT use `import` or `export` (it is not an ES module; those silently fail to render). " \
40
+ "Put JSX in <script type='text/babel'>, define a component, and you MUST mount it yourself with: " \
41
+ "ReactDOM.createRoot(document.getElementById('root')).render(<App />); " \
42
+ "BIDIRECTIONAL: PromptObjects.send('...') is available inside the artifact — wire it to " \
43
+ "buttons/forms/controls so the human can talk back to YOU through the UI instead of chatting " \
44
+ "(messages arrive from 'artifact:<title>'). Respond to them by re-rendering this artifact " \
45
+ "(mode 'replace') with the updated UI. A re-render resets the artifact's local JS state, so " \
46
+ "bake the current state into the HTML you render. " \
47
+ "Default mode is 'replace' — same title updates in place. Use mode 'version' for a new entry each time."
48
+ end
49
+
50
+ def parameters
51
+ {
52
+ type: "object",
53
+ properties: {
54
+ title: {
55
+ type: "string",
56
+ description: "Short title for the artifact tab. In replace mode, this is the unique identifier — same title overwrites the previous version."
57
+ },
58
+ html: {
59
+ type: "string",
60
+ description: "Your component markup only — NOT a full page. React 18/ReactDOM/Babel/Tailwind " \
61
+ "and a <div id='root'> are already provided by the iframe; do NOT add <html>/<head>/<body> " \
62
+ "or your own <script src=...> CDN tags. No `import`/`export`. Put JSX in <script type='text/babel'> " \
63
+ "and END with a mount, e.g.: function App(){return <div className='p-4'>…</div>} " \
64
+ "ReactDOM.createRoot(document.getElementById('root')).render(<App />); — without that mount nothing shows."
65
+ },
66
+ mode: {
67
+ type: "string",
68
+ enum: %w[replace version],
69
+ description: "replace (default): update existing artifact with same title. version: always create a new artifact entry."
70
+ }
71
+ },
72
+ required: %w[title html]
73
+ }
74
+ end
75
+
76
+ def receive(message, context:)
77
+ title = message[:title] || message["title"]
78
+ html = message[:html] || message["html"]
79
+ mode = message[:mode] || message["mode"] || "replace"
80
+
81
+ return "Error: 'title' is required" unless title
82
+ return "Error: 'html' is required" unless html
83
+
84
+ return "Error: artifact persistence is unavailable" unless context.env.respond_to?(:persist_artifact)
85
+
86
+ context.env.persist_artifact(title: title, html: html, mode: mode, context: context)
87
+ "Artifact '#{title}' rendered (#{mode}) in the UI."
88
+ end
89
+ end
90
+ end
91
+ end
@@ -3,7 +3,7 @@
3
3
  module PromptObjects
4
4
  module Universal
5
5
  # Universal capability to request a primitive from the human.
6
- # Similar to ask_human but specifically for requesting new tools.
6
+ # Requests explicit approval before installing a new tool implementation.
7
7
  # The human can approve, modify, or reject the request.
8
8
  class RequestPrimitive < Primitive
9
9
  def name
@@ -2,15 +2,25 @@
2
2
 
3
3
  module PromptObjects
4
4
  module Universal
5
- # Universal capability to store shared data scoped to the current delegation chain.
5
+ # Universal capability to create or update shared data scoped to the current delegation chain.
6
6
  # Any PO in the same delegation tree can read this data via get_env_data or list_env_data.
7
- class StoreEnvData < Primitive
7
+ # Replaces the previous store_env_data and update_env_data (which were redundant).
8
+ class SetEnvData < Primitive
9
+ execution_policy(
10
+ parallel_safe: true,
11
+ side_effect: :write,
12
+ resource_keys: ->(arguments, context, _capability) {
13
+ key = arguments[:key] || arguments["key"]
14
+ ["workspace:#{context.workspace_session_id}:env_data:#{key}"]
15
+ }
16
+ )
17
+
8
18
  def name
9
- "store_env_data"
19
+ "set_env_data"
10
20
  end
11
21
 
12
22
  def description
13
- "Store a key-value pair in the shared environment data for this delegation chain. " \
23
+ "Create or update a key-value pair in the shared environment data. " \
14
24
  "All POs in the same delegation tree can access this data. " \
15
25
  "If the key already exists, it will be overwritten."
16
26
  end
@@ -38,13 +48,14 @@ module PromptObjects
38
48
  def receive(message, context:)
39
49
  key = message[:key] || message["key"]
40
50
  short_description = message[:short_description] || message["short_description"]
41
- value = message[:value] || message["value"]
51
+ # Key-presence check, not `||`, so a literal `false` value isn't dropped.
52
+ value = message.key?(:value) ? message[:value] : message["value"]
42
53
 
43
54
  return "Error: 'key' is required" unless key
44
55
  return "Error: 'short_description' is required" unless short_description
45
56
  return "Error: 'value' is required" if value.nil?
46
57
 
47
- root_thread_id = resolve_root_thread(context)
58
+ root_thread_id = context.env_data_scope
48
59
  return "Error: Could not resolve thread scope (no active session)" unless root_thread_id
49
60
 
50
61
  store = context.env.session_store
@@ -52,6 +63,21 @@ module PromptObjects
52
63
 
53
64
  stored_by = context.calling_po || "unknown"
54
65
 
66
+ if context.env.respond_to?(:set_environment_data)
67
+ context.env.set_environment_data(
68
+ key: key,
69
+ short_description: short_description,
70
+ value: value,
71
+ context: context
72
+ )
73
+ context.bus.publish(
74
+ from: stored_by,
75
+ to: "env_data",
76
+ message: { action: "set", key: key, short_description: short_description }
77
+ )
78
+ return "Stored '#{key}' in environment data."
79
+ end
80
+
55
81
  store.store_env_data(
56
82
  root_thread_id: root_thread_id,
57
83
  key: key,
@@ -63,25 +89,13 @@ module PromptObjects
63
89
  context.bus.publish(
64
90
  from: stored_by,
65
91
  to: "env_data",
66
- message: { action: "store", key: key, short_description: short_description }
92
+ message: { action: "set", key: key, short_description: short_description }
67
93
  )
68
94
 
69
- context.env.notify_env_data_changed(action: "store", root_thread_id: root_thread_id, key: key, stored_by: stored_by)
95
+ context.env.notify_env_data_changed(action: "set", root_thread_id: root_thread_id, key: key, stored_by: stored_by)
70
96
 
71
97
  "Stored '#{key}' in environment data."
72
98
  end
73
-
74
- private
75
-
76
- def resolve_root_thread(context)
77
- store = context.env.session_store
78
- return nil unless store
79
-
80
- po = context.env.registry.get(context.calling_po)
81
- return nil unless po&.respond_to?(:session_id) && po.session_id
82
-
83
- store.resolve_root_thread(po.session_id)
84
- end
85
99
  end
86
100
  end
87
101
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PromptObjects
4
+ VERSION = "0.7.0"
5
+ end
@@ -4,6 +4,9 @@ require "openai"
4
4
  require "anthropic"
5
5
  require "front_matter_parser"
6
6
  require "json"
7
+ require "digest"
8
+
9
+ require_relative "prompt_objects/version"
7
10
 
8
11
  # PromptObjects: A framework where markdown files with LLM-backed behavior
9
12
  # act as first-class autonomous entities.
@@ -11,11 +14,12 @@ module PromptObjects
11
14
  class Error < StandardError; end
12
15
 
13
16
  # Universal capabilities available to all prompt objects (don't need to be declared)
14
- UNIVERSAL_CAPABILITIES = %w[ask_human think create_capability add_capability remove_capability list_capabilities list_primitives add_primitive create_primitive delete_primitive verify_primitive modify_primitive request_primitive modify_prompt store_env_data get_env_data list_env_data update_env_data delete_env_data].freeze
17
+ UNIVERSAL_CAPABILITIES = %w[create_capability add_capability remove_capability list_capabilities delete_primitive verify_primitive modify_primitive request_primitive modify_prompt set_env_data get_env_data list_env_data delete_env_data render_artifact dispatch_po get_run_status join_runs].freeze
15
18
  end
16
19
 
17
20
  require_relative "prompt_objects/capability"
18
21
  require_relative "prompt_objects/primitive"
22
+ require_relative "prompt_objects/service"
19
23
  require_relative "prompt_objects/registry"
20
24
  require_relative "prompt_objects/message_bus"
21
25
  require_relative "prompt_objects/human_queue"
@@ -26,7 +30,17 @@ require_relative "prompt_objects/llm/anthropic_adapter"
26
30
  require_relative "prompt_objects/llm/gemini_adapter"
27
31
  require_relative "prompt_objects/llm/factory"
28
32
  require_relative "prompt_objects/llm/pricing"
33
+ require_relative "prompt_objects/execution/contracts"
34
+ require_relative "prompt_objects/execution/context"
35
+ require_relative "prompt_objects/execution/blocking_executor"
36
+ require_relative "prompt_objects/execution/permit_pool"
37
+ require_relative "prompt_objects/execution/scheduler"
38
+ require_relative "prompt_objects/execution/policy"
39
+ require_relative "prompt_objects/execution/resource_lock_manager"
40
+ require_relative "prompt_objects/domain/records"
29
41
  require_relative "prompt_objects/prompt_object"
42
+ require_relative "prompt_objects/operations/diagnostics"
43
+ require_relative "prompt_objects/operations/retention"
30
44
 
31
45
  # Environment module (must be loaded before environment.rb which uses them)
32
46
  require_relative "prompt_objects/environment/manifest"
@@ -38,33 +52,44 @@ require_relative "prompt_objects/environment"
38
52
 
39
53
  # Session storage
40
54
  require_relative "prompt_objects/session/store"
55
+ require_relative "prompt_objects/repositories/base_repository"
56
+ require_relative "prompt_objects/repositories/workspace_session_repository"
57
+ require_relative "prompt_objects/repositories/thread_repository"
58
+ require_relative "prompt_objects/repositories/run_repository"
59
+ require_relative "prompt_objects/repositories/definition_repository"
60
+ require_relative "prompt_objects/repositories/message_repository"
61
+ require_relative "prompt_objects/repositories/event_repository"
62
+ require_relative "prompt_objects/repositories/tool_execution_repository"
63
+ require_relative "prompt_objects/repositories/artifact_repository"
64
+ require_relative "prompt_objects/repositories/env_data_repository"
65
+ require_relative "prompt_objects/operations/run_trace_builder"
66
+ require_relative "prompt_objects/execution/runner"
41
67
 
42
68
  # Built-in primitives
43
69
  require_relative "prompt_objects/primitives/read_file"
44
70
  require_relative "prompt_objects/primitives/list_files"
45
71
  require_relative "prompt_objects/primitives/write_file"
46
72
  require_relative "prompt_objects/primitives/http_get"
73
+ require_relative "prompt_objects/primitives/think"
47
74
 
48
75
  # Universal capabilities (available to all prompt objects)
49
- require_relative "prompt_objects/universal/ask_human"
50
- require_relative "prompt_objects/universal/think"
51
76
  require_relative "prompt_objects/universal/create_capability"
52
77
  require_relative "prompt_objects/universal/add_capability"
53
78
  require_relative "prompt_objects/universal/remove_capability"
54
79
  require_relative "prompt_objects/universal/list_capabilities"
55
- require_relative "prompt_objects/universal/list_primitives"
56
- require_relative "prompt_objects/universal/add_primitive"
57
- require_relative "prompt_objects/universal/create_primitive"
58
80
  require_relative "prompt_objects/universal/delete_primitive"
59
81
  require_relative "prompt_objects/universal/verify_primitive"
60
82
  require_relative "prompt_objects/universal/modify_primitive"
61
83
  require_relative "prompt_objects/universal/request_primitive"
62
84
  require_relative "prompt_objects/universal/modify_prompt"
63
- require_relative "prompt_objects/universal/store_env_data"
85
+ require_relative "prompt_objects/universal/set_env_data"
64
86
  require_relative "prompt_objects/universal/get_env_data"
65
87
  require_relative "prompt_objects/universal/list_env_data"
66
- require_relative "prompt_objects/universal/update_env_data"
67
88
  require_relative "prompt_objects/universal/delete_env_data"
89
+ require_relative "prompt_objects/universal/render_artifact"
90
+ require_relative "prompt_objects/universal/dispatch_po"
91
+ require_relative "prompt_objects/universal/get_run_status"
92
+ require_relative "prompt_objects/universal/join_runs"
68
93
 
69
94
  # Connectors (different interfaces to environments)
70
95
  require_relative "prompt_objects/connectors/base"
@@ -32,17 +32,21 @@ When you need a quick file listing without deep analysis:
32
32
  - Use list_files directly
33
33
 
34
34
  When someone needs help that no existing specialist can provide:
35
- - Use ask_human to confirm creating a new specialist
36
- - Use create_capability to create a new specialist prompt object
35
+ - Inspect and delegate to existing specialists first
36
+ - Use create_capability to create a focused specialist only when none fits
37
37
  - The new specialist will then be available for future use
38
38
 
39
39
  When you're unsure what to do:
40
40
  - Use think to reason through the problem
41
- - Use ask_human to clarify with the user
41
+ - Inspect available tools and delegate the uncertain part to the most relevant specialist
42
+
43
+ When work spans several steps or specialists:
44
+ - Render a status artifact with render_artifact and keep it current
45
+ - Wire buttons to PromptObjects.send so the human can steer by clicking
42
46
 
43
47
  ## Notes
44
48
 
45
49
  You believe in the right capability for the right job.
46
50
  You're proud when your team works well together.
47
51
  You keep your own responses brief - let the specialists shine.
48
- You can create new specialists when needed, but always ask the human first.
52
+ You can create new specialists when needed, after confirming that no existing specialist fits.