runspace 0.2.0__tar.gz

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 (310) hide show
  1. runspace-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +40 -0
  2. runspace-0.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. runspace-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
  4. runspace-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  5. runspace-0.2.0/.github/workflows/release.yml +52 -0
  6. runspace-0.2.0/.github/workflows/tests.yml +129 -0
  7. runspace-0.2.0/.gitignore +33 -0
  8. runspace-0.2.0/CHANGELOG.md +156 -0
  9. runspace-0.2.0/CLAUDE.md +82 -0
  10. runspace-0.2.0/CODE_OF_CONDUCT.md +42 -0
  11. runspace-0.2.0/CONTRIBUTING.md +55 -0
  12. runspace-0.2.0/LICENSE +202 -0
  13. runspace-0.2.0/NOTICE +17 -0
  14. runspace-0.2.0/PKG-INFO +297 -0
  15. runspace-0.2.0/README.md +208 -0
  16. runspace-0.2.0/SECURITY.md +36 -0
  17. runspace-0.2.0/conftest.py +55 -0
  18. runspace-0.2.0/docs/4-RUNTIME-RECIPE.md +393 -0
  19. runspace-0.2.0/docs/AGENT_CREATION_GUIDE.md +190 -0
  20. runspace-0.2.0/docs/NEW_APP_BOILERPLATE.md +197 -0
  21. runspace-0.2.0/docs/PUBLISHING.md +160 -0
  22. runspace-0.2.0/docs/VISION_GUIDE.md +179 -0
  23. runspace-0.2.0/docs/WEB_CRAWLING_GUIDE.md +148 -0
  24. runspace-0.2.0/docs/adr/0001-adapter-pattern.md +251 -0
  25. runspace-0.2.0/docs/adr/0002-mcp-ui-block-integrity.md +91 -0
  26. runspace-0.2.0/examples/grid/README.md +57 -0
  27. runspace-0.2.0/examples/grid/agents/_grid.py +95 -0
  28. runspace-0.2.0/examples/grid/agents/analyst/SOUL.md +44 -0
  29. runspace-0.2.0/examples/grid/agents/analyst/tools/grid.py +163 -0
  30. runspace-0.2.0/examples/grid/routines.yml +31 -0
  31. runspace-0.2.0/examples/grid/workspace.yml +21 -0
  32. runspace-0.2.0/pyproject.toml +182 -0
  33. runspace-0.2.0/scripts/agent_smoke.py +363 -0
  34. runspace-0.2.0/scripts/agents_inspect.py +194 -0
  35. runspace-0.2.0/scripts/render_tool_docs.py +180 -0
  36. runspace-0.2.0/scripts/tests/__init__.py +0 -0
  37. runspace-0.2.0/scripts/tests/test_agent_smoke.py +376 -0
  38. runspace-0.2.0/scripts/tests/test_agents_inspect.py +148 -0
  39. runspace-0.2.0/scripts/tests/test_render_tool_docs.py +150 -0
  40. runspace-0.2.0/scripts/tests/test_tools_diff.py +293 -0
  41. runspace-0.2.0/scripts/tools_diff.py +267 -0
  42. runspace-0.2.0/scripts/tools_usage.py +148 -0
  43. runspace-0.2.0/src/runspace/__init__.py +11 -0
  44. runspace-0.2.0/src/runspace/contracts/__init__.py +69 -0
  45. runspace-0.2.0/src/runspace/contracts/chat.py +80 -0
  46. runspace-0.2.0/src/runspace/contracts/runtime.py +94 -0
  47. runspace-0.2.0/src/runspace/contracts/scheduling.py +239 -0
  48. runspace-0.2.0/src/runspace/contracts/tests/__init__.py +0 -0
  49. runspace-0.2.0/src/runspace/contracts/tests/test_chat.py +77 -0
  50. runspace-0.2.0/src/runspace/contracts/tests/test_no_runtime_leaks.py +174 -0
  51. runspace-0.2.0/src/runspace/contracts/tests/test_runtime.py +62 -0
  52. runspace-0.2.0/src/runspace/contracts/tests/test_scheduling.py +99 -0
  53. runspace-0.2.0/src/runspace/contracts/tests/test_tool.py +93 -0
  54. runspace-0.2.0/src/runspace/contracts/tests/test_workspace.py +97 -0
  55. runspace-0.2.0/src/runspace/contracts/tool.py +68 -0
  56. runspace-0.2.0/src/runspace/contracts/workspace.py +91 -0
  57. runspace-0.2.0/src/runspace/helpers/__init__.py +0 -0
  58. runspace-0.2.0/src/runspace/helpers/bootstrap.py +257 -0
  59. runspace-0.2.0/src/runspace/helpers/documents/__init__.py +0 -0
  60. runspace-0.2.0/src/runspace/helpers/documents/article_reader.py +290 -0
  61. runspace-0.2.0/src/runspace/helpers/documents/branded_pdf.py +244 -0
  62. runspace-0.2.0/src/runspace/helpers/documents/store.py +113 -0
  63. runspace-0.2.0/src/runspace/helpers/messaging/__init__.py +0 -0
  64. runspace-0.2.0/src/runspace/helpers/messaging/messages.py +32 -0
  65. runspace-0.2.0/src/runspace/helpers/session/__init__.py +0 -0
  66. runspace-0.2.0/src/runspace/helpers/session/store.py +102 -0
  67. runspace-0.2.0/src/runspace/helpers/supabase_db.py +161 -0
  68. runspace-0.2.0/src/runspace/helpers/supabase_exec_sql.sql +42 -0
  69. runspace-0.2.0/src/runspace/helpers/web_crawler/__init__.py +40 -0
  70. runspace-0.2.0/src/runspace/helpers/web_crawler/core.py +292 -0
  71. runspace-0.2.0/src/runspace/ingestion/README.md +67 -0
  72. runspace-0.2.0/src/runspace/ingestion/__init__.py +39 -0
  73. runspace-0.2.0/src/runspace/ingestion/_redact.py +29 -0
  74. runspace-0.2.0/src/runspace/ingestion/_render.py +267 -0
  75. runspace-0.2.0/src/runspace/ingestion/buffer.py +126 -0
  76. runspace-0.2.0/src/runspace/ingestion/pairing.py +378 -0
  77. runspace-0.2.0/src/runspace/ingestion/polling.py +299 -0
  78. runspace-0.2.0/src/runspace/ingestion/routes.py +69 -0
  79. runspace-0.2.0/src/runspace/ingestion/telegram.py +1299 -0
  80. runspace-0.2.0/src/runspace/ingestion/transport.py +184 -0
  81. runspace-0.2.0/src/runspace/protocols/README.md +119 -0
  82. runspace-0.2.0/src/runspace/protocols/__init__.py +133 -0
  83. runspace-0.2.0/src/runspace/protocols/clock.py +92 -0
  84. runspace-0.2.0/src/runspace/protocols/config.py +342 -0
  85. runspace-0.2.0/src/runspace/protocols/conversations/__init__.py +32 -0
  86. runspace-0.2.0/src/runspace/protocols/conversations/in_memory.py +121 -0
  87. runspace-0.2.0/src/runspace/protocols/conversations/models.py +66 -0
  88. runspace-0.2.0/src/runspace/protocols/conversations/protocol.py +71 -0
  89. runspace-0.2.0/src/runspace/protocols/conversations/schema.sql +35 -0
  90. runspace-0.2.0/src/runspace/protocols/conversations/supabase_conversations.py +187 -0
  91. runspace-0.2.0/src/runspace/protocols/embeddings/__init__.py +30 -0
  92. runspace-0.2.0/src/runspace/protocols/embeddings/fixture.py +65 -0
  93. runspace-0.2.0/src/runspace/protocols/embeddings/openai_compat.py +48 -0
  94. runspace-0.2.0/src/runspace/protocols/embeddings/protocol.py +52 -0
  95. runspace-0.2.0/src/runspace/protocols/file_storage/__init__.py +37 -0
  96. runspace-0.2.0/src/runspace/protocols/file_storage/local.py +165 -0
  97. runspace-0.2.0/src/runspace/protocols/file_storage/protocol.py +78 -0
  98. runspace-0.2.0/src/runspace/protocols/file_storage/supabase.py +146 -0
  99. runspace-0.2.0/src/runspace/protocols/prompt/__init__.py +25 -0
  100. runspace-0.2.0/src/runspace/protocols/prompt/envelope.py +49 -0
  101. runspace-0.2.0/src/runspace/protocols/prompt/flatten.py +124 -0
  102. runspace-0.2.0/src/runspace/protocols/prompt/tests/__init__.py +0 -0
  103. runspace-0.2.0/src/runspace/protocols/prompt/tests/test_envelope.py +45 -0
  104. runspace-0.2.0/src/runspace/protocols/prompt/tests/test_flatten.py +71 -0
  105. runspace-0.2.0/src/runspace/protocols/prompt/tests/test_real_tenants.py +132 -0
  106. runspace-0.2.0/src/runspace/protocols/registry.py +146 -0
  107. runspace-0.2.0/src/runspace/protocols/sandbox_lint.py +126 -0
  108. runspace-0.2.0/src/runspace/protocols/store/__init__.py +15 -0
  109. runspace-0.2.0/src/runspace/protocols/store/file_store.py +134 -0
  110. runspace-0.2.0/src/runspace/protocols/store/in_memory.py +82 -0
  111. runspace-0.2.0/src/runspace/protocols/store/protocol.py +58 -0
  112. runspace-0.2.0/src/runspace/protocols/store/supabase_store.py +106 -0
  113. runspace-0.2.0/src/runspace/protocols/tests/__init__.py +0 -0
  114. runspace-0.2.0/src/runspace/protocols/tests/fixtures/vision/sample_invoice.jpg +0 -0
  115. runspace-0.2.0/src/runspace/protocols/tests/fixtures/vision/sample_invoice.json +10 -0
  116. runspace-0.2.0/src/runspace/protocols/tests/test_clock.py +153 -0
  117. runspace-0.2.0/src/runspace/protocols/tests/test_codex_vision_pdf.py +104 -0
  118. runspace-0.2.0/src/runspace/protocols/tests/test_config.py +263 -0
  119. runspace-0.2.0/src/runspace/protocols/tests/test_e2e_agent_flow.py +205 -0
  120. runspace-0.2.0/src/runspace/protocols/tests/test_embeddings.py +233 -0
  121. runspace-0.2.0/src/runspace/protocols/tests/test_file_inbox_transport.py +151 -0
  122. runspace-0.2.0/src/runspace/protocols/tests/test_file_storage.py +139 -0
  123. runspace-0.2.0/src/runspace/protocols/tests/test_file_storage_property.py +150 -0
  124. runspace-0.2.0/src/runspace/protocols/tests/test_file_store.py +152 -0
  125. runspace-0.2.0/src/runspace/protocols/tests/test_fixture_vision.py +88 -0
  126. runspace-0.2.0/src/runspace/protocols/tests/test_lazy_backend_imports.py +153 -0
  127. runspace-0.2.0/src/runspace/protocols/tests/test_multitenant_isolation.py +288 -0
  128. runspace-0.2.0/src/runspace/protocols/tests/test_package_includes.py +86 -0
  129. runspace-0.2.0/src/runspace/protocols/tests/test_registry.py +73 -0
  130. runspace-0.2.0/src/runspace/protocols/tests/test_store_contract.py +240 -0
  131. runspace-0.2.0/src/runspace/protocols/tests/test_supabase_store_42p10_fallback.py +120 -0
  132. runspace-0.2.0/src/runspace/protocols/tests/test_transcriber.py +72 -0
  133. runspace-0.2.0/src/runspace/protocols/tests/test_vision_snapshot.py +134 -0
  134. runspace-0.2.0/src/runspace/protocols/transcriber.py +44 -0
  135. runspace-0.2.0/src/runspace/protocols/transport/__init__.py +27 -0
  136. runspace-0.2.0/src/runspace/protocols/transport/file_inbox.py +91 -0
  137. runspace-0.2.0/src/runspace/protocols/transport/protocol.py +74 -0
  138. runspace-0.2.0/src/runspace/protocols/transport/telegram.py +123 -0
  139. runspace-0.2.0/src/runspace/protocols/vision/__init__.py +23 -0
  140. runspace-0.2.0/src/runspace/protocols/vision/codex_vision.py +156 -0
  141. runspace-0.2.0/src/runspace/protocols/vision/fixture_vision.py +64 -0
  142. runspace-0.2.0/src/runspace/protocols/vision/protocol.py +38 -0
  143. runspace-0.2.0/src/runspace/py.typed +0 -0
  144. runspace-0.2.0/src/runspace/runspace_cli/__init__.py +90 -0
  145. runspace-0.2.0/src/runspace/runspace_cli/tests/__init__.py +0 -0
  146. runspace-0.2.0/src/runspace/runspace_cli/tests/test_dispatcher.py +116 -0
  147. runspace-0.2.0/src/runspace/templates/widgets.md +70 -0
  148. runspace-0.2.0/src/runspace/workspace/README.md +83 -0
  149. runspace-0.2.0/src/runspace/workspace/__init__.py +31 -0
  150. runspace-0.2.0/src/runspace/workspace/backend/__init__.py +25 -0
  151. runspace-0.2.0/src/runspace/workspace/backend/_mcp_ui.py +106 -0
  152. runspace-0.2.0/src/runspace/workspace/backend/activity_log.py +73 -0
  153. runspace-0.2.0/src/runspace/workspace/backend/app_registry.py +415 -0
  154. runspace-0.2.0/src/runspace/workspace/backend/attachments.py +224 -0
  155. runspace-0.2.0/src/runspace/workspace/backend/bootstrap.py +402 -0
  156. runspace-0.2.0/src/runspace/workspace/backend/file_extractors.py +154 -0
  157. runspace-0.2.0/src/runspace/workspace/backend/gateway.py +2263 -0
  158. runspace-0.2.0/src/runspace/workspace/backend/history_sqlite.py +142 -0
  159. runspace-0.2.0/src/runspace/workspace/backend/media.py +59 -0
  160. runspace-0.2.0/src/runspace/workspace/backend/messaging.py +455 -0
  161. runspace-0.2.0/src/runspace/workspace/backend/messaging_sqlite.py +411 -0
  162. runspace-0.2.0/src/runspace/workspace/backend/models.py +30 -0
  163. runspace-0.2.0/src/runspace/workspace/backend/pricing.py +94 -0
  164. runspace-0.2.0/src/runspace/workspace/backend/registry.py +246 -0
  165. runspace-0.2.0/src/runspace/workspace/backend/response_filter.py +41 -0
  166. runspace-0.2.0/src/runspace/workspace/backend/routines_store.py +362 -0
  167. runspace-0.2.0/src/runspace/workspace/backend/runners/__init__.py +0 -0
  168. runspace-0.2.0/src/runspace/workspace/backend/runners/ab.py +122 -0
  169. runspace-0.2.0/src/runspace/workspace/backend/runners/base.py +104 -0
  170. runspace-0.2.0/src/runspace/workspace/backend/runners/executor.py +133 -0
  171. runspace-0.2.0/src/runspace/workspace/backend/runners/loader.py +123 -0
  172. runspace-0.2.0/src/runspace/workspace/backend/runners/workload.py +166 -0
  173. runspace-0.2.0/src/runspace/workspace/backend/runtimes/__init__.py +20 -0
  174. runspace-0.2.0/src/runspace/workspace/backend/runtimes/agentino.py +425 -0
  175. runspace-0.2.0/src/runspace/workspace/backend/runtimes/claude_code.py +269 -0
  176. runspace-0.2.0/src/runspace/workspace/backend/runtimes/codex.py +230 -0
  177. runspace-0.2.0/src/runspace/workspace/backend/runtimes/mcp_harness.py +220 -0
  178. runspace-0.2.0/src/runspace/workspace/backend/runtimes/openclaw.py +277 -0
  179. runspace-0.2.0/src/runspace/workspace/backend/runtimes/pi.py +298 -0
  180. runspace-0.2.0/src/runspace/workspace/backend/scoring/__init__.py +0 -0
  181. runspace-0.2.0/src/runspace/workspace/backend/scoring/base.py +51 -0
  182. runspace-0.2.0/src/runspace/workspace/backend/scoring/match.py +55 -0
  183. runspace-0.2.0/src/runspace/workspace/backend/sessions.py +314 -0
  184. runspace-0.2.0/src/runspace/workspace/backend/tests/__init__.py +0 -0
  185. runspace-0.2.0/src/runspace/workspace/backend/tests/test_advanced.py +452 -0
  186. runspace-0.2.0/src/runspace/workspace/backend/tests/test_app_registry_no_runtime_imports.py +96 -0
  187. runspace-0.2.0/src/runspace/workspace/backend/tests/test_bootstrap.py +385 -0
  188. runspace-0.2.0/src/runspace/workspace/backend/tests/test_channel_message_persistence.py +258 -0
  189. runspace-0.2.0/src/runspace/workspace/backend/tests/test_chat_persistence_and_attachments.py +209 -0
  190. runspace-0.2.0/src/runspace/workspace/backend/tests/test_chat_stream_disconnect.py +199 -0
  191. runspace-0.2.0/src/runspace/workspace/backend/tests/test_claude_code_runtime.py +229 -0
  192. runspace-0.2.0/src/runspace/workspace/backend/tests/test_codex_runtime.py +226 -0
  193. runspace-0.2.0/src/runspace/workspace/backend/tests/test_documentation_samples.py +74 -0
  194. runspace-0.2.0/src/runspace/workspace/backend/tests/test_documented_imports.py +252 -0
  195. runspace-0.2.0/src/runspace/workspace/backend/tests/test_documents_mirror.py +118 -0
  196. runspace-0.2.0/src/runspace/workspace/backend/tests/test_examples.py +95 -0
  197. runspace-0.2.0/src/runspace/workspace/backend/tests/test_external_channel_telegram.py +294 -0
  198. runspace-0.2.0/src/runspace/workspace/backend/tests/test_external_channels_transport.py +448 -0
  199. runspace-0.2.0/src/runspace/workspace/backend/tests/test_frontend_layering.py +183 -0
  200. runspace-0.2.0/src/runspace/workspace/backend/tests/test_gate_manager_wiring.py +216 -0
  201. runspace-0.2.0/src/runspace/workspace/backend/tests/test_gateway.py +324 -0
  202. runspace-0.2.0/src/runspace/workspace/backend/tests/test_history_sqlite.py +124 -0
  203. runspace-0.2.0/src/runspace/workspace/backend/tests/test_markdown_renderer_contract.py +61 -0
  204. runspace-0.2.0/src/runspace/workspace/backend/tests/test_mcp_ui_fences.py +74 -0
  205. runspace-0.2.0/src/runspace/workspace/backend/tests/test_media.py +87 -0
  206. runspace-0.2.0/src/runspace/workspace/backend/tests/test_messaging_sqlite.py +181 -0
  207. runspace-0.2.0/src/runspace/workspace/backend/tests/test_openclaw_runtime.py +140 -0
  208. runspace-0.2.0/src/runspace/workspace/backend/tests/test_pairing_and_callbacks.py +1941 -0
  209. runspace-0.2.0/src/runspace/workspace/backend/tests/test_pdf_chat_context_hint.py +83 -0
  210. runspace-0.2.0/src/runspace/workspace/backend/tests/test_pi_runtime.py +306 -0
  211. runspace-0.2.0/src/runspace/workspace/backend/tests/test_pricing.py +72 -0
  212. runspace-0.2.0/src/runspace/workspace/backend/tests/test_register_soul_flattening.py +146 -0
  213. runspace-0.2.0/src/runspace/workspace/backend/tests/test_registry_mount.py +80 -0
  214. runspace-0.2.0/src/runspace/workspace/backend/tests/test_resolve_files_original_name.py +83 -0
  215. runspace-0.2.0/src/runspace/workspace/backend/tests/test_response_filter.py +48 -0
  216. runspace-0.2.0/src/runspace/workspace/backend/tests/test_routines_store.py +370 -0
  217. runspace-0.2.0/src/runspace/workspace/backend/tests/test_runners.py +407 -0
  218. runspace-0.2.0/src/runspace/workspace/backend/tests/test_secrets_stay_out_of_prompts.py +88 -0
  219. runspace-0.2.0/src/runspace/workspace/backend/tests/test_soul_includes.py +104 -0
  220. runspace-0.2.0/src/runspace/workspace/backend/tests/test_std_bundles.py +71 -0
  221. runspace-0.2.0/src/runspace/workspace/backend/tests/test_token_redaction.py +110 -0
  222. runspace-0.2.0/src/runspace/workspace/backend/tests/test_tools_usage.py +256 -0
  223. runspace-0.2.0/src/runspace/workspace/backend/tests/test_widget_validator.py +118 -0
  224. runspace-0.2.0/src/runspace/workspace/backend/tests/test_workspace.py +365 -0
  225. runspace-0.2.0/src/runspace/workspace/backend/tools_usage.py +145 -0
  226. runspace-0.2.0/src/runspace/workspace/backend/widget_validator.py +128 -0
  227. runspace-0.2.0/src/runspace/workspace/cli/__init__.py +10 -0
  228. runspace-0.2.0/src/runspace/workspace/cli/__main__.py +81 -0
  229. runspace-0.2.0/src/runspace/workspace/cli/init_cmd.py +293 -0
  230. runspace-0.2.0/src/runspace/workspace/cli/tests/__init__.py +0 -0
  231. runspace-0.2.0/src/runspace/workspace/cli/tests/test_console_scripts.py +51 -0
  232. runspace-0.2.0/src/runspace/workspace/cli/tests/test_init_cmd.py +193 -0
  233. runspace-0.2.0/src/runspace/workspace/plugin.py +54 -0
  234. runspace-0.2.0/src/runspace/workspace/serve.py +74 -0
  235. runspace-0.2.0/templates/workspace.yml.example +28 -0
  236. runspace-0.2.0/tests/conftest.py +1 -0
  237. runspace-0.2.0/tests/test_conversations.py +97 -0
  238. runspace-0.2.0/tests/test_create_tools_comprehensive.py +285 -0
  239. runspace-0.2.0/tests/test_shared_tools_filestorage_migration.py +178 -0
  240. runspace-0.2.0/tests/test_shared_tools_storage_refactor.py +296 -0
  241. runspace-0.2.0/tests/test_telegram_render.py +287 -0
  242. runspace-0.2.0/workspace/frontend/.npmrc +3 -0
  243. runspace-0.2.0/workspace/frontend/dialog/components/AgentPicker.tsx +73 -0
  244. runspace-0.2.0/workspace/frontend/dialog/components/DialogComposer.tsx +413 -0
  245. runspace-0.2.0/workspace/frontend/dialog/components/DialogMessageRow.tsx +146 -0
  246. runspace-0.2.0/workspace/frontend/dialog/components/ThreadListSidebar.tsx +181 -0
  247. runspace-0.2.0/workspace/frontend/dialog/components/index.ts +5 -0
  248. runspace-0.2.0/workspace/frontend/dialog/components/threadStore.ts +223 -0
  249. runspace-0.2.0/workspace/frontend/dialog/hooks/useThreads.ts +89 -0
  250. runspace-0.2.0/workspace/frontend/dialog/pages/DialogChat.tsx +403 -0
  251. runspace-0.2.0/workspace/frontend/dialog/pages/index.ts +1 -0
  252. runspace-0.2.0/workspace/frontend/index.d.ts +279 -0
  253. runspace-0.2.0/workspace/frontend/package.json +40 -0
  254. runspace-0.2.0/workspace/frontend/shared/api-proxies/generate.sh +100 -0
  255. runspace-0.2.0/workspace/frontend/shared/components/BotAvatar.tsx +30 -0
  256. runspace-0.2.0/workspace/frontend/shared/components/BotPopover.tsx +75 -0
  257. runspace-0.2.0/workspace/frontend/shared/components/DateDivider.tsx +32 -0
  258. runspace-0.2.0/workspace/frontend/shared/components/InlineChart.tsx +392 -0
  259. runspace-0.2.0/workspace/frontend/shared/components/InlineMermaid.tsx +64 -0
  260. runspace-0.2.0/workspace/frontend/shared/components/InlineTable.tsx +398 -0
  261. runspace-0.2.0/workspace/frontend/shared/components/InsightCard.tsx +103 -0
  262. runspace-0.2.0/workspace/frontend/shared/components/KPIBlock.tsx +69 -0
  263. runspace-0.2.0/workspace/frontend/shared/components/KPICard.tsx +31 -0
  264. runspace-0.2.0/workspace/frontend/shared/components/MarkdownContent.test.js +159 -0
  265. runspace-0.2.0/workspace/frontend/shared/components/MarkdownContent.tsx +126 -0
  266. runspace-0.2.0/workspace/frontend/shared/components/MessageActions.tsx +105 -0
  267. runspace-0.2.0/workspace/frontend/shared/components/MessageBubble.tsx +259 -0
  268. runspace-0.2.0/workspace/frontend/shared/components/MessageComposer.tsx +430 -0
  269. runspace-0.2.0/workspace/frontend/shared/components/ToolBadge.tsx +13 -0
  270. runspace-0.2.0/workspace/frontend/shared/components/TypingIndicator.tsx +42 -0
  271. runspace-0.2.0/workspace/frontend/shared/components/index.ts +23 -0
  272. runspace-0.2.0/workspace/frontend/shared/components/parseChartConfig.test.js +276 -0
  273. runspace-0.2.0/workspace/frontend/shared/components/parseChartConfig.ts +154 -0
  274. runspace-0.2.0/workspace/frontend/shared/components/widgetIntent.tsx +74 -0
  275. runspace-0.2.0/workspace/frontend/shared/hooks/useChannelMessages.ts +184 -0
  276. runspace-0.2.0/workspace/frontend/shared/hooks/useChatStream.ts +203 -0
  277. runspace-0.2.0/workspace/frontend/shared/hooks/useLocalState.ts +79 -0
  278. runspace-0.2.0/workspace/frontend/shared/utils/describeSchedule.test.mjs +39 -0
  279. runspace-0.2.0/workspace/frontend/shared/utils/describeSchedule.ts +45 -0
  280. runspace-0.2.0/workspace/frontend/shared/utils/loosePayload.test.mjs +72 -0
  281. runspace-0.2.0/workspace/frontend/shared/utils/loosePayload.ts +117 -0
  282. runspace-0.2.0/workspace/frontend/team/components/DashboardPanel.tsx +131 -0
  283. runspace-0.2.0/workspace/frontend/team/components/Kanban.tsx +176 -0
  284. runspace-0.2.0/workspace/frontend/team/components/KnowledgeBrowser.tsx +220 -0
  285. runspace-0.2.0/workspace/frontend/team/components/ModeSwitcher.tsx +50 -0
  286. runspace-0.2.0/workspace/frontend/team/components/ResizeHandle.tsx +66 -0
  287. runspace-0.2.0/workspace/frontend/team/components/Sidebar.tsx +269 -0
  288. runspace-0.2.0/workspace/frontend/team/components/ThreadPanel.tsx +136 -0
  289. runspace-0.2.0/workspace/frontend/team/components/index.ts +7 -0
  290. runspace-0.2.0/workspace/frontend/team/components/settings/GatewayStatusWidget.tsx +105 -0
  291. runspace-0.2.0/workspace/frontend/team/components/settings/KeyValueWidget.tsx +39 -0
  292. runspace-0.2.0/workspace/frontend/team/components/settings/NumberPairWidget.tsx +44 -0
  293. runspace-0.2.0/workspace/frontend/team/components/settings/ScheduleWidget.tsx +71 -0
  294. runspace-0.2.0/workspace/frontend/team/components/settings/TextWidget.tsx +27 -0
  295. runspace-0.2.0/workspace/frontend/team/components/settings/ToggleListWidget.tsx +36 -0
  296. runspace-0.2.0/workspace/frontend/team/components/settings/examples/GatewayStatusWidget.tsx +128 -0
  297. runspace-0.2.0/workspace/frontend/team/components/settings/examples/README.md +28 -0
  298. runspace-0.2.0/workspace/frontend/team/components/settings/examples/ScheduleWidget.tsx +54 -0
  299. runspace-0.2.0/workspace/frontend/team/components/settings/index.ts +7 -0
  300. runspace-0.2.0/workspace/frontend/team/pages/ActivityLogPage.tsx +113 -0
  301. runspace-0.2.0/workspace/frontend/team/pages/AgentChat.tsx +438 -0
  302. runspace-0.2.0/workspace/frontend/team/pages/BotDMPage.tsx +18 -0
  303. runspace-0.2.0/workspace/frontend/team/pages/ChannelPage.tsx +194 -0
  304. runspace-0.2.0/workspace/frontend/team/pages/GeneralChannel.tsx +617 -0
  305. runspace-0.2.0/workspace/frontend/team/pages/RoutinesPage.tsx +217 -0
  306. runspace-0.2.0/workspace/frontend/team/pages/SettingsPage.tsx +163 -0
  307. runspace-0.2.0/workspace/frontend/team/pages/TeamGrid.tsx +46 -0
  308. runspace-0.2.0/workspace/frontend/team/pages/WorkspaceLayout.tsx +233 -0
  309. runspace-0.2.0/workspace/frontend/team/pages/WorkspaceShell.tsx +205 -0
  310. runspace-0.2.0/workspace/frontend/team/pages/index.ts +10 -0
@@ -0,0 +1,40 @@
1
+ name: Bug report
2
+ description: Something behaves differently from what the docs say
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what-happened
7
+ attributes:
8
+ label: What happened
9
+ description: What you did, what you expected, and what you got instead.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: reproduce
14
+ attributes:
15
+ label: Minimal reproduction
16
+ description: >
17
+ The smallest script or config that shows the problem. This is the
18
+ single most useful thing you can include.
19
+ render: python
20
+ validations:
21
+ required: true
22
+ - type: input
23
+ id: version
24
+ attributes:
25
+ label: Version
26
+ description: Release number or commit SHA.
27
+ validations:
28
+ required: true
29
+ - type: input
30
+ id: python
31
+ attributes:
32
+ label: Python version
33
+ placeholder: "3.12.3"
34
+ validations:
35
+ required: true
36
+ - type: textarea
37
+ id: traceback
38
+ attributes:
39
+ label: Traceback or logs
40
+ render: text
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/islavutin-oss/runspace/security/advisories/new
5
+ about: Report privately, not as a public issue.
@@ -0,0 +1,23 @@
1
+ name: Feature request
2
+ description: Propose a change to what Runspace does
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: The problem
9
+ description: >
10
+ What are you trying to do that is awkward or impossible today?
11
+ Describe the situation, not the solution.
12
+ validations:
13
+ required: true
14
+ - type: textarea
15
+ id: proposal
16
+ attributes:
17
+ label: What you have in mind
18
+ description: If you have an API or config shape in mind, sketch it.
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: What you tried instead
23
+ description: Workarounds you have used, and why they fall short.
@@ -0,0 +1,15 @@
1
+ ## What this changes
2
+
3
+ <!-- One paragraph. What is different after this lands? -->
4
+
5
+ ## Why
6
+
7
+ <!-- The reasoning a reviewer cannot get from the diff. Link the issue if
8
+ there is one. -->
9
+
10
+ ## Checklist
11
+
12
+ - [ ] Tests cover the change, and a bug fix has a test that failed before it
13
+ - [ ] `pytest` passes locally
14
+ - [ ] `ruff check .` and `ruff format --check .` pass
15
+ - [ ] Docs updated if behaviour or configuration changed
@@ -0,0 +1,52 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write # to attach build artifacts to the release
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+ - run: pip install build twine
20
+ - run: python -m build
21
+ - run: twine check dist/*
22
+ - uses: actions/upload-artifact@v4
23
+ with:
24
+ name: dist
25
+ path: dist/
26
+ - name: Attach the artifacts to the release
27
+ if: github.event_name == 'release'
28
+ run: gh release upload "$GITHUB_REF_NAME" dist/*
29
+ env:
30
+ GH_TOKEN: ${{ github.token }}
31
+
32
+ # Publishing is a separate job so a build failure never leaves a partial
33
+ # upload, and so the PyPI credential is scoped to this job alone. It uses
34
+ # Trusted Publishing (OIDC) — there is no API token stored in the repo.
35
+ #
36
+ # Before the first run, configure a pending publisher on PyPI:
37
+ # https://pypi.org/manage/account/publishing/
38
+ # owner: <the GitHub owner> repository: runspace
39
+ # workflow: release.yml environment: pypi
40
+ publish:
41
+ needs: build
42
+ if: github.event_name == 'release'
43
+ runs-on: ubuntu-latest
44
+ environment: pypi
45
+ permissions:
46
+ id-token: write # required for Trusted Publishing
47
+ steps:
48
+ - uses: actions/download-artifact@v4
49
+ with:
50
+ name: dist
51
+ path: dist/
52
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,129 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ env:
16
+ # The test job checks out agentino beside this repo. That step needs
17
+ # agentino to be public, or a token with access to it — until then this
18
+ # job cannot run on a fork or a fresh clone.
19
+ AGENTINO_REF: main
20
+
21
+ jobs:
22
+ lint:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.12"
29
+ - run: pip install ruff
30
+ - name: ruff check
31
+ run: ruff check .
32
+ - name: ruff format --check
33
+ run: ruff format --check .
34
+
35
+ test:
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: actions/checkout@v4
44
+ with:
45
+ repository: islavutin-oss/agentino
46
+ ref: ${{ env.AGENTINO_REF }}
47
+ path: _agentino
48
+ - uses: actions/setup-python@v5
49
+ with:
50
+ python-version: ${{ matrix.python-version }}
51
+ - name: Install dependencies
52
+ run: |
53
+ # Install through the package's own metadata, not a hand-kept list.
54
+ # A hand-kept list makes CI green while `pip install runspace` is
55
+ # broken, which is exactly how two missing core dependencies once
56
+ # went unnoticed. Every extra except [agentino] is installed from
57
+ # pyproject; the runtime comes from the checkout beside us because
58
+ # it is not on PyPI during CI.
59
+ # The document tools live in agentino's [docgen] extra.
60
+ pip install "./_agentino[docgen]"
61
+ pip install -e ".[redis,server,supabase,workspace,documents,scheduler,crawler,dev]"
62
+ pip install pytest-timeout
63
+ # testpaths in pyproject covers every test location, so one run is the
64
+ # whole suite. It used to be two commands and the second was easy to
65
+ # skip, which let a broken console-script entry point sit unnoticed.
66
+ - name: pytest
67
+ env:
68
+ PYTHONPATH: "src"
69
+ run: pytest -q
70
+ - name: sandbox_lint self-test
71
+ env:
72
+ PYTHONPATH: "src"
73
+ run: python -m runspace.protocols.sandbox_lint .
74
+
75
+ build:
76
+ runs-on: ubuntu-latest
77
+ steps:
78
+ - uses: actions/checkout@v4
79
+ - uses: actions/setup-python@v5
80
+ with:
81
+ python-version: "3.12"
82
+ - run: pip install build twine
83
+ - name: Build the distribution
84
+ run: python -m build
85
+ - name: Check the distribution metadata
86
+ run: twine check dist/*
87
+
88
+ frontend:
89
+ runs-on: ubuntu-latest
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+ - uses: actions/setup-node@v4
93
+ with:
94
+ node-version: "22"
95
+ - name: Frontend unit tests
96
+ run: |
97
+ node --experimental-strip-types workspace/frontend/shared/utils/loosePayload.test.mjs
98
+ node --experimental-strip-types --test workspace/frontend/shared/utils/describeSchedule.test.mjs
99
+
100
+ installable:
101
+ # Guards the one thing the test suite cannot see: that the built
102
+ # distribution is usable by someone who runs `pip install runspace`
103
+ # with nothing else present.
104
+ runs-on: ubuntu-latest
105
+ steps:
106
+ - uses: actions/checkout@v4
107
+ - uses: actions/setup-python@v5
108
+ with:
109
+ python-version: "3.12"
110
+ - run: pip install build
111
+ - name: Build the wheel
112
+ run: python -m build --wheel --outdir dist
113
+ - name: Install it into an empty environment
114
+ run: |
115
+ python -m venv /tmp/clean
116
+ /tmp/clean/bin/pip install dist/*.whl
117
+ - name: Import it with no agent runtime installed
118
+ run: |
119
+ cd /tmp
120
+ /tmp/clean/bin/python -c "
121
+ import runspace, runspace.contracts, runspace.protocols
122
+ try:
123
+ import agentino
124
+ raise SystemExit('agentino must not be a core dependency')
125
+ except ImportError:
126
+ pass
127
+ from runspace.protocols import get_store, get_vision, get_transport
128
+ print(type(get_store()).__name__, type(get_vision()).__name__, type(get_transport()).__name__)
129
+ "
@@ -0,0 +1,33 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ node_modules/
5
+ .pytest_cache/
6
+
7
+ # Runtime artifacts
8
+ sessions/
9
+ sessions.jsonl
10
+ usage.jsonl
11
+ .agentino/
12
+ .docs/
13
+
14
+ # Build artifacts
15
+ dist/
16
+ build/
17
+ *.egg-info/
18
+ *.so
19
+ *.c
20
+ !setup.c
21
+ agentino_pkg/
22
+
23
+ # Large repos cloned by agents
24
+
25
+ # Local scratch / experiments — not part of the shared package.
26
+ _tmp/
27
+ vscode-extension/
28
+
29
+ # Tooling caches
30
+ .venv/
31
+ .ruff_cache/
32
+ .hypothesis/
33
+ .runspace/
@@ -0,0 +1,156 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project aims
5
+ to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from 1.0
6
+ onward.
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - A SQLite messaging backend, now the default. Channels, threads, direct
13
+ messages and read state previously required `SUPABASE_URL` and
14
+ `SUPABASE_KEY`: without them `MessagingService` was never constructed, every
15
+ channel route returned 404 and nothing persisted. Since channels are the
16
+ workspace's main surface, a fresh install looked broken rather than
17
+ unconfigured. Supabase is still used when it is configured.
18
+ - `InsightCard` reports a payload that parsed but is not an insight, naming
19
+ the keys it did receive. It previously rendered an empty card, which reads
20
+ as a layout bug rather than a malformed block.
21
+
22
+ - Apache-2.0 licence, `NOTICE`, contribution guide, security policy, code of
23
+ conduct, and issue and pull-request templates.
24
+ - `response_filter` in `workspace.yml`: a dotted path to a callable the
25
+ application owns. Runspace resolves and calls it without knowing what it
26
+ checks.
27
+ - `max_turns` as per-app configuration, defaulting to 10.
28
+ - `gpt-5.4-codex` is the default model for the agent runtimes and vision.
29
+ - `WorkspaceRegistry.mount(app)`: exposes every tenant's gateway routes on one
30
+ application, resolving the tenant per request. A single-tenant host could
31
+ already do `app.include_router(gateway.router)`; a multi-tenant one had no
32
+ supported way, so hosts hand-wrote a handful of routes and quietly exposed a
33
+ fraction of the surface — channels, messages, uploads, pairings and the
34
+ external-channel routes simply had no route at all. The documentation
35
+ described this method before it existed.
36
+ - Built-in `gateway_status` and `schedule` settings widgets. Both types were
37
+ named in `SettingsPage`'s union from the start and neither had an
38
+ implementation, so a section declaring either rendered "Unknown widget
39
+ type". An application can still replace either by passing a widget of the
40
+ same name.
41
+ - `examples/grid`: a complete workspace that runs on a free, keyless public API
42
+ the moment a model endpoint is configured. A test walks every shipped example
43
+ and checks the paths its config names exist, its runtime is one the registry
44
+ dispatches, and its README names the command that starts it.
45
+ - Opening suggestions in `workspace.yml`, carried through `/config`, so a
46
+ dialog client shows the workspace's own questions rather than generic ones.
47
+ - `py.typed`. Without it a type checker ignores every annotation in the
48
+ package, so a hundred annotated modules did nothing for a consumer.
49
+
50
+ ### Changed
51
+
52
+ - **Breaking: one import root.** The packages moved under `src/runspace/`, so
53
+ everything is imported as `runspace.*`. The distribution previously installed
54
+ `contracts`, `protocols`, `workspace`, `ingestion`, `helpers` and
55
+ `runspace_cli` as top-level names, which would collide with a user's own
56
+ modules. Consumers update with:
57
+
58
+ from protocols import get_store -> from runspace.protocols import get_store
59
+ from workspace.backend import ... -> from runspace.workspace.backend import ...
60
+
61
+ No compatibility shim ships. Aliasing the old names in `sys.modules` made
62
+ submodule imports execute a second time under a second name, giving two
63
+ module objects with separate caches — a worse failure than an ImportError.
64
+
65
+ `workspace/frontend/` stays at the repository root: it is the `@runspace/ui`
66
+ npm package, not part of the Python tree.
67
+ - Zero-configuration defaults. `STORE_BACKEND` defaults to `file` (rooted at
68
+ `./.runspace/store`), `VISION_BACKEND` to `fixture` and `TRANSPORT_BACKEND`
69
+ to `file`, so a fresh install runs with no environment set. Previously the
70
+ store defaulted to `supabase` and raised on import without credentials.
71
+ Deployments relying on the old defaults must set them explicitly.
72
+ - Licence changed from MIT to Apache-2.0. The repository previously declared
73
+ MIT in metadata with no licence file present.
74
+ - Environment variables are no longer named after particular deployments. The
75
+ embeddings and vision adapters read `EMBEDDINGS_*`, `AI_BASE_URL`,
76
+ `AI_API_KEY` and `VISION_API_KEY`.
77
+ - CI runs `ruff`, covers Python 3.10 through 3.13, exercises all six test
78
+ directories rather than one, builds the distribution with a `twine`
79
+ metadata check, and runs the frontend parser tests.
80
+
81
+ ### Fixed
82
+
83
+ - The distribution declared a dependency on `agentino`, which on PyPI is an
84
+ unrelated project. Neither package is published to PyPI; install is from git. The agent runtime is now the `[agentino]` extra, pulling
85
+ `agentino-framework` — Runspace routes each turn to whichever runtime an app
86
+ declares and requires none of them, so it does not belong in the core
87
+ requirements.
88
+ - `pip install runspace` produced an install that could not be imported:
89
+ `contracts.scheduling` needs `croniter` and `protocols.config` needs
90
+ `pydantic-settings`, both of which had been arriving transitively through
91
+ agentino. Both are now declared. Verified by installing the wheel into an
92
+ empty virtualenv with no agent runtime present.
93
+
94
+ - `gateway.py` used `Any` in six annotations without importing it, which
95
+ raises under `typing.get_type_hints()`.
96
+ - The multi-tenant isolation property tests shared a single store across every
97
+ hypothesis example. Rows accumulated, so a tenant id generated as `tenant_a`
98
+ in one example could reappear as `tenant_b` in a later one and read as a
99
+ leak. Each example now builds its own store.
100
+ - `tests/test_telegram_render.py` imported a package path that never resolved,
101
+ so the module could not be collected at all.
102
+ - A test fixture repeated the `token` key in one dictionary literal.
103
+ - A test drove its coroutines through `asyncio.get_event_loop()`, which on
104
+ Python 3.12 only works when an earlier test left a loop on the thread, so it
105
+ passed or failed depending on collection order.
106
+ - The `[supabase]` extra was documented but never declared, and `[documents]`
107
+ omitted pymupdf, which the scanned-PDF path imports.
108
+ - The widget-integrity regex covered `chart`, `datatable` and `kpi` but not
109
+ `insight`, which the frontend also renders. An insight block the model
110
+ mangled was never spliced back over — the canonical copy was appended at
111
+ the end instead, so the page showed a parse error above the real card.
112
+ - Seventeen test modules computed a `sys.path` entry from `parents[N]`. The
113
+ indices were wrong after the move, and one of them put `src/runspace` on the
114
+ path, making every subpackage importable a second time as a top-level name.
115
+ Path setup now lives once in the root `conftest.py`.
116
+ - The agent answered twice in a channel. Posting to `/channels/{slug}/messages`
117
+ dispatches `@mentions`, and the channel UI also streams its own turn, so once
118
+ the channel routes were reachable every mention produced two model calls and
119
+ two stored replies. The POST now honours `dispatch=false`.
120
+ - `runspace init` produced a workspace that would not boot. The generated
121
+ config named `tenants.<id>.plugins.health`, which is not an importable module
122
+ path when the id contains a hyphen and assumed a working directory the
123
+ printed instructions do not use. The prompts also raised an unhandled
124
+ `EOFError` when stdin was not a tty, so the command died half-scaffolded in
125
+ CI or a Dockerfile.
126
+ - The `sandbox_lint` CI step ran `python -m protocols.sandbox_lint`, a module
127
+ path the rename removed, so that job could never have passed.
128
+ - The documented development setup produced a checkout whose tests could not
129
+ collect, and `[dev]` named a package that is not on PyPI, so the obvious
130
+ correction failed outright.
131
+ - Eight tests silently skipped because they looked for the frontend inside the
132
+ Python package and named a layer that had been renamed. Two layering rules
133
+ ran green while checking a directory that no longer existed, so a shared
134
+ component importing from `team/` passed the rule forbidding exactly that.
135
+ - Twenty file paths named in the documentation pointed at files that are not
136
+ in the repository, including a package renamed two versions ago.
137
+ - Tests shared one storage root and one adapter registry, so state leaked
138
+ between them. An autouse fixture now gives each test its own roots and
139
+ resets the cached adapters.
140
+
141
+ ### Removed
142
+
143
+ - The `packages/` split distributions. `packages/runspace` claimed the same
144
+ PyPI name as the repository root with an older version and a subset of the
145
+ code, so only one of them could ever own that name. Both also produced
146
+ broken source distributions: their `force-include` pointed at `../../src`,
147
+ which does not exist inside an extracted sdist, so a source install failed
148
+ to build a wheel. The root distribution supersedes both.
149
+
150
+ - Product-specific policy from the shared runtime: hardcoded nudge strings in
151
+ one natural language, refusal markers, a datatable row cap naming one
152
+ application's chart tools, and a fixed `max_turns=25` applied to every app.
153
+ - Internal planning documents that tracked a migration through internal
154
+ phases and named host paths, ticket numbers and unshipped projects.
155
+ - Twelve test guards that read a directory which had moved to
156
+ `agentino.tools.std`. The equivalent guards now live in that repository.
@@ -0,0 +1,82 @@
1
+ # CLAUDE.md — Runspace
2
+
3
+ Notes for coding agents (and humans) working in this repository.
4
+
5
+ ## What this is
6
+
7
+ A workspace runtime for agents: a FastAPI gateway, an app registry, chat with
8
+ streaming and attachments, external channels, scheduled routines, and a React
9
+ frontend. It is runtime-agnostic by construction — the agentino adapter is one
10
+ runtime among several, and `app_registry.py` contains no `from agentino`
11
+ imports.
12
+
13
+ ## Setup
14
+
15
+ ```bash
16
+ python -m venv .venv && source .venv/bin/activate
17
+ pip install -e ".[workspace]"
18
+ pip install pytest pytest-asyncio hypothesis ruff
19
+ ```
20
+
21
+ Agentino is an optional extra, not a dependency — `pip install -e ".[agentino]"`
22
+ if you want the in-process runtime. The test suite exercises it, so install it
23
+ for development.
24
+
25
+ ## Commands
26
+
27
+ ```bash
28
+ PYTHONPATH=src pytest -q # default paths
29
+ PYTHONPATH=src pytest src/runspace/contracts src/runspace/protocols \
30
+ src/runspace/workspace/cli/tests scripts/tests -q
31
+ node --experimental-strip-types workspace/frontend/shared/utils/loosePayload.test.mjs
32
+
33
+ ruff check . # must be clean
34
+ ruff format --check . # must be clean
35
+ PYTHONPATH=src python -m runspace.protocols.sandbox_lint <dir> # flag banned imports in agent tools
36
+ ```
37
+
38
+ CI runs all of these.
39
+
40
+ ## Layout
41
+
42
+ ```
43
+ runspace/
44
+ ├── src/runspace/ one import root — everything ships as runspace.*
45
+ │ ├── contracts/ wire shapes — chat, runtime, tool, workspace.yml
46
+ │ ├── protocols/ swappable adapters behind Protocols:
47
+ │ │ store, vision, transport, file_storage, embeddings,
48
+ │ │ transcriber, clock, prompt flattening
49
+ │ ├── workspace/backend/ gateway (FastAPI routes), app_registry, runtimes/,
50
+ │ │ messaging, routines, attachments, runners, scoring
51
+ │ ├── ingestion/ inbound channels — Telegram polling, pairing
52
+ │ ├── helpers/ session, messaging and document utilities
53
+ │ └── runspace_cli/ the `runspace` console entry point
54
+ ├── workspace/frontend/ React components published as @runspace/ui — an npm
55
+ │ package, deliberately outside the Python tree
56
+ └── templates/ workspace.yml.example
57
+ ```
58
+
59
+ ## Conventions that matter here
60
+
61
+ - **No application logic.** This is a shared layer. Tenant behaviour comes
62
+ from configuration — `workspace.yml`, `routines.yml`, `SOUL.md` — never from
63
+ a branch in Python. That includes prompt wording, retry thresholds, tool
64
+ names and natural language. Where an application needs to influence
65
+ behaviour, give it a seam: `response_filter` names a callable the app owns,
66
+ and runspace calls it without knowing what it checks.
67
+ - **No hardcoded prompts.** Agent instructions live in `SOUL.md`. Frontend
68
+ rendering rules live in a partial the SOUL includes, not in a Python
69
+ constant.
70
+ - **No deployment-specific environment variables.** The public names are
71
+ `AI_BASE_URL` / `AI_API_KEY`, `EMBEDDINGS_*` and `VISION_API_KEY`. Use
72
+ `${VAR:-default}` in YAML; `_resolve_env_vars` expands it at load time.
73
+ - **Runtime-agnostic by construction.** Only
74
+ `src/runspace/workspace/backend/runtimes/agentino.py` imports agentino, and it is one of
75
+ five adapters — `codex`, `claude_code`, `pi` and `openclaw` shell out to a
76
+ CLI instead. `app_registry.py` dispatches on `app.type` and imports none of
77
+ them eagerly. A sixth drops in beside them.
78
+ - **One source of truth for prompts.** `protocols.prompt.flatten_soul` is what
79
+ every caller uses to produce a flattened SOUL, so they cannot drift.
80
+ - **Property tests build their own fixtures.** `@given` runs many examples
81
+ against one function-scoped fixture, so shared mutable state leaks between
82
+ examples and looks like a bug in the code under test. Hand back a factory.
@@ -0,0 +1,42 @@
1
+ # Code of Conduct
2
+
3
+ ## Our pledge
4
+
5
+ We want participation in this project to be a harassment-free experience for
6
+ everyone, whatever their age, body size, disability, ethnicity, sex
7
+ characteristics, gender identity and expression, level of experience,
8
+ education, socio-economic status, nationality, personal appearance, race,
9
+ religion, or sexual identity and orientation.
10
+
11
+ ## Our standards
12
+
13
+ Things that help:
14
+
15
+ - being welcoming and respectful of differing viewpoints
16
+ - accepting constructive criticism gracefully
17
+ - focusing on what is best for the project
18
+ - showing empathy toward other people
19
+
20
+ Things that are not acceptable:
21
+
22
+ - sexualised language or imagery, and unwelcome sexual attention
23
+ - trolling, insults, derogatory comments, and personal or political attacks
24
+ - public or private harassment
25
+ - publishing someone's private information without explicit permission
26
+
27
+ ## Enforcement
28
+
29
+ Report unacceptable behaviour by contacting the maintainer,
30
+ [@islavutin-oss](https://github.com/islavutin-oss), through a GitHub private message
31
+ or a private security advisory on this repository. All reports are reviewed
32
+ and investigated, and will be kept confidential.
33
+
34
+ Maintainers may remove comments, commits, code, issues and other
35
+ contributions that violate this Code of Conduct, and may ban contributors
36
+ temporarily or permanently for behaviour they judge inappropriate,
37
+ threatening, offensive or harmful.
38
+
39
+ ## Attribution
40
+
41
+ Adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
42
+ version 1.4.
@@ -0,0 +1,55 @@
1
+ # Contributing to Runspace
2
+
3
+ Thanks for taking the time. This is a small project, so the process is short.
4
+
5
+ ## Before you start
6
+
7
+ For anything beyond a bug fix or a typo, **open an issue first**. It is much
8
+ less painful to disagree about an approach in an issue than in a finished
9
+ pull request.
10
+
11
+ ## Getting set up
12
+
13
+ ```bash
14
+ git clone https://github.com/islavutin-oss/runspace.git
15
+ cd runspace
16
+ python -m venv .venv && source .venv/bin/activate
17
+ pip install -e ".[dev]"
18
+ ```
19
+
20
+ Run the tests and the linter:
21
+
22
+ ```bash
23
+ PYTHONPATH=src pytest -q
24
+ ruff check .
25
+ ruff format --check .
26
+ ```
27
+
28
+ CI runs exactly these, on Python 3.10 through 3.13.
29
+
30
+ ## What a good pull request looks like
31
+
32
+ - **One change per pull request.** Unrelated fixes bundled together are hard
33
+ to review and harder to revert.
34
+ - **Tests come with the change.** A bug fix should include a test that fails
35
+ before it and passes after.
36
+ - **The suite is green.** Not "green except for a flaky one" — if something
37
+ is flaky, that is worth an issue of its own.
38
+ - **Commit messages say what changed and why.** The subject line is
39
+ imperative and under about 72 characters; the body explains the reasoning
40
+ a reviewer cannot get from the diff.
41
+
42
+ We use [Conventional Commits](https://www.conventionalcommits.org) prefixes:
43
+ `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:`, `ci:`.
44
+
45
+ ## Style
46
+
47
+ The linter settles formatting arguments, so there is nothing to debate:
48
+ `ruff format` owns line width, `ruff check` owns the rest. Type hints on
49
+ public functions. Comments should explain why something is the way it is —
50
+ the code already says what it does.
51
+
52
+ ## Licensing
53
+
54
+ Contributions are accepted under the [Apache License 2.0](LICENSE), the same
55
+ licence the project ships under. There is no CLA.