hud-python 0.2.10__tar.gz → 0.3.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.

Potentially problematic release.


This version of hud-python might be problematic. Click here for more details.

Files changed (257) hide show
  1. {hud_python-0.2.10 → hud_python-0.3.0}/.github/workflows/ci.yml +14 -1
  2. {hud_python-0.2.10 → hud_python-0.3.0}/.gitignore +2 -0
  3. {hud_python-0.2.10 → hud_python-0.3.0}/PKG-INFO +9 -6
  4. hud_python-0.3.0/environments/README.md +163 -0
  5. hud_python-0.3.0/environments/simple_browser/.dockerignore +52 -0
  6. hud_python-0.3.0/environments/simple_browser/.gitignore +100 -0
  7. hud_python-0.3.0/environments/simple_browser/DEPLOYMENT.md +159 -0
  8. hud_python-0.3.0/environments/simple_browser/Dockerfile +38 -0
  9. hud_python-0.3.0/environments/simple_browser/README.md +261 -0
  10. hud_python-0.3.0/environments/simple_browser/apps/README.md +135 -0
  11. hud_python-0.3.0/environments/simple_browser/apps/todo/README.md +85 -0
  12. hud_python-0.3.0/environments/simple_browser/apps/todo/backend/main.py +329 -0
  13. hud_python-0.3.0/environments/simple_browser/apps/todo/backend/pyproject.toml +15 -0
  14. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/app/globals.css +3 -0
  15. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/app/layout.tsx +22 -0
  16. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/app/page.tsx +169 -0
  17. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/next.config.js +13 -0
  18. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/package-lock.json +6040 -0
  19. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/package.json +28 -0
  20. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/postcss.config.js +6 -0
  21. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/tailwind.config.js +12 -0
  22. hud_python-0.3.0/environments/simple_browser/apps/todo/frontend/tsconfig.json +26 -0
  23. hud_python-0.3.0/environments/simple_browser/apps/todo/launch.py +286 -0
  24. hud_python-0.3.0/environments/simple_browser/docker-compose.yml +13 -0
  25. hud_python-0.3.0/environments/simple_browser/pyproject.toml +26 -0
  26. hud_python-0.3.0/environments/simple_browser/src/hud_controller/README.md +117 -0
  27. hud_python-0.3.0/environments/simple_browser/src/hud_controller/__init__.py +3 -0
  28. hud_python-0.3.0/environments/simple_browser/src/hud_controller/__main__.py +13 -0
  29. hud_python-0.3.0/environments/simple_browser/src/hud_controller/evaluators/__init__.py +18 -0
  30. hud_python-0.3.0/environments/simple_browser/src/hud_controller/evaluators/context.py +210 -0
  31. hud_python-0.3.0/environments/simple_browser/src/hud_controller/evaluators/registry.py +150 -0
  32. hud_python-0.3.0/environments/simple_browser/src/hud_controller/evaluators/todo.py +255 -0
  33. hud_python-0.3.0/environments/simple_browser/src/hud_controller/problems/__init__.py +9 -0
  34. hud_python-0.3.0/environments/simple_browser/src/hud_controller/problems/registry.py +123 -0
  35. hud_python-0.3.0/environments/simple_browser/src/hud_controller/problems/todo.py +162 -0
  36. hud_python-0.3.0/environments/simple_browser/src/hud_controller/runtime.py +191 -0
  37. hud_python-0.3.0/environments/simple_browser/src/hud_controller/server.py +388 -0
  38. hud_python-0.3.0/environments/simple_browser/src/hud_controller/services.py +312 -0
  39. hud_python-0.3.0/environments/simple_browser/src/hud_controller/setup/__init__.py +10 -0
  40. hud_python-0.3.0/environments/simple_browser/src/hud_controller/setup/registry.py +124 -0
  41. hud_python-0.3.0/environments/simple_browser/src/hud_controller/setup/todo.py +180 -0
  42. hud_python-0.3.0/environments/simple_browser/start.sh +19 -0
  43. {hud_python-0.2.10 → hud_python-0.3.0}/examples/README.md +5 -6
  44. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/agents_tools}/browser_use.ipynb +1 -1
  45. hud_python-0.3.0/examples/agents_tools/mcp_claude_agent.py +71 -0
  46. hud_python-0.3.0/examples/agents_tools/mcp_openai_agent.py +59 -0
  47. hud_python-0.3.0/examples/agents_tools/mcp_use_agent.py +50 -0
  48. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/agents_tools}/sensitive_data.ipynb +1 -1
  49. hud_python-0.3.0/examples/agents_tools/simple_task_example.py +136 -0
  50. hud_python-0.3.0/examples/environments/gmail_local.py +66 -0
  51. hud_python-0.3.0/examples/environments/resources_example.py +342 -0
  52. hud_python-0.3.0/examples/environments/simple_browser_example.py +138 -0
  53. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/evaluations}/wordle_example.ipynb +4 -4
  54. {hud_python-0.2.10 → hud_python-0.3.0}/examples/sheets_bench_cua_example.ipynb +15 -45
  55. {hud_python-0.2.10 → hud_python-0.3.0}/hud/__init__.py +14 -5
  56. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/docker_client.py +1 -1
  57. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/environment.py +10 -7
  58. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/local_docker_client.py +1 -1
  59. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/remote_client.py +1 -1
  60. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/remote_docker_client.py +2 -2
  61. {hud_python-0.2.10 → hud_python-0.3.0}/hud/exceptions.py +2 -1
  62. hud_python-0.3.0/hud/mcp_agent/__init__.py +15 -0
  63. hud_python-0.3.0/hud/mcp_agent/base.py +723 -0
  64. hud_python-0.3.0/hud/mcp_agent/claude.py +316 -0
  65. hud_python-0.3.0/hud/mcp_agent/langchain.py +231 -0
  66. hud_python-0.3.0/hud/mcp_agent/openai.py +318 -0
  67. hud_python-0.3.0/hud/mcp_agent/tests/__init__.py +1 -0
  68. hud_python-0.3.0/hud/mcp_agent/tests/test_base.py +437 -0
  69. {hud_python-0.2.10 → hud_python-0.3.0}/hud/settings.py +14 -2
  70. {hud_python-0.2.10 → hud_python-0.3.0}/hud/task.py +4 -0
  71. hud_python-0.3.0/hud/telemetry/__init__.py +25 -0
  72. hud_python-0.3.0/hud/telemetry/_trace.py +184 -0
  73. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/context.py +9 -27
  74. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/exporter.py +6 -5
  75. hud_python-0.3.0/hud/telemetry/instrumentation/mcp.py +259 -0
  76. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/mcp_models.py +13 -74
  77. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/tests/test_context.py +9 -6
  78. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/tests/test_trace.py +92 -61
  79. hud_python-0.3.0/hud/tools/__init__.py +21 -0
  80. hud_python-0.3.0/hud/tools/base.py +65 -0
  81. hud_python-0.3.0/hud/tools/bash.py +137 -0
  82. hud_python-0.3.0/hud/tools/computer/__init__.py +13 -0
  83. hud_python-0.3.0/hud/tools/computer/anthropic.py +411 -0
  84. hud_python-0.3.0/hud/tools/computer/hud.py +315 -0
  85. hud_python-0.3.0/hud/tools/computer/openai.py +283 -0
  86. hud_python-0.3.0/hud/tools/edit.py +290 -0
  87. hud_python-0.3.0/hud/tools/executors/__init__.py +13 -0
  88. hud_python-0.3.0/hud/tools/executors/base.py +331 -0
  89. hud_python-0.3.0/hud/tools/executors/pyautogui.py +585 -0
  90. hud_python-0.3.0/hud/tools/executors/tests/__init__.py +1 -0
  91. hud_python-0.3.0/hud/tools/executors/tests/test_base_executor.py +338 -0
  92. hud_python-0.3.0/hud/tools/executors/tests/test_pyautogui_executor.py +162 -0
  93. hud_python-0.3.0/hud/tools/executors/xdo.py +503 -0
  94. hud_python-0.3.0/hud/tools/helper/README.md +56 -0
  95. hud_python-0.3.0/hud/tools/helper/__init__.py +9 -0
  96. hud_python-0.3.0/hud/tools/helper/mcp_server.py +78 -0
  97. hud_python-0.3.0/hud/tools/helper/server_initialization.py +115 -0
  98. hud_python-0.3.0/hud/tools/helper/utils.py +58 -0
  99. hud_python-0.3.0/hud/tools/playwright_tool.py +373 -0
  100. hud_python-0.3.0/hud/tools/tests/__init__.py +3 -0
  101. hud_python-0.3.0/hud/tools/tests/test_bash.py +152 -0
  102. hud_python-0.3.0/hud/tools/tests/test_computer.py +52 -0
  103. hud_python-0.3.0/hud/tools/tests/test_computer_actions.py +34 -0
  104. hud_python-0.3.0/hud/tools/tests/test_edit.py +233 -0
  105. hud_python-0.3.0/hud/tools/tests/test_init.py +27 -0
  106. hud_python-0.3.0/hud/tools/tests/test_playwright_tool.py +183 -0
  107. hud_python-0.3.0/hud/tools/tests/test_tools.py +154 -0
  108. hud_python-0.3.0/hud/tools/tests/test_utils.py +156 -0
  109. hud_python-0.3.0/hud/tools/utils.py +50 -0
  110. {hud_python-0.2.10 → hud_python-0.3.0}/hud/types.py +10 -1
  111. hud_python-0.3.0/hud/utils/tests/test_init.py +21 -0
  112. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/test_version.py +1 -1
  113. {hud_python-0.2.10 → hud_python-0.3.0}/hud/version.py +1 -1
  114. {hud_python-0.2.10 → hud_python-0.3.0}/pyproject.toml +12 -8
  115. hud_python-0.2.10/environments/novnc_ubuntu/Dockerfile +0 -8
  116. hud_python-0.2.10/environments/novnc_ubuntu/pyproject.toml +0 -17
  117. hud_python-0.2.10/environments/novnc_ubuntu/src/hud_controller/__init__.py +0 -7
  118. hud_python-0.2.10/environments/novnc_ubuntu/src/hud_controller/pyautogui_rosetta.py +0 -378
  119. hud_python-0.2.10/environments/novnc_ubuntu/src/hud_controller/step.py +0 -34
  120. hud_python-0.2.10/examples/appflowy.ipynb +0 -1552
  121. hud_python-0.2.10/examples/custom_task_example.ipynb +0 -77
  122. hud_python-0.2.10/examples/jobs.ipynb +0 -73
  123. hud_python-0.2.10/examples/local.ipynb +0 -67
  124. hud_python-0.2.10/hud/telemetry/__init__.py +0 -21
  125. hud_python-0.2.10/hud/telemetry/_trace.py +0 -173
  126. hud_python-0.2.10/hud/telemetry/instrumentation/mcp.py +0 -495
  127. {hud_python-0.2.10 → hud_python-0.3.0}/.env.example +0 -0
  128. {hud_python-0.2.10 → hud_python-0.3.0}/.github/workflows/release.yml +0 -0
  129. {hud_python-0.2.10 → hud_python-0.3.0}/LICENSE +0 -0
  130. {hud_python-0.2.10 → hud_python-0.3.0}/MANIFEST.in +0 -0
  131. {hud_python-0.2.10 → hud_python-0.3.0}/README.md +0 -0
  132. {hud_python-0.2.10 → hud_python-0.3.0}/docs/advanced/cla-details.mdx +0 -0
  133. {hud_python-0.2.10 → hud_python-0.3.0}/docs/advanced/environment-control.mdx +0 -0
  134. {hud_python-0.2.10 → hud_python-0.3.0}/docs/advanced/tracing.mdx +0 -0
  135. {hud_python-0.2.10 → hud_python-0.3.0}/docs/advanced/uploading.mdx +0 -0
  136. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/adapters.mdx +0 -0
  137. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/env.mdx +0 -0
  138. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/gym.mdx +0 -0
  139. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/job.mdx +0 -0
  140. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/task.mdx +0 -0
  141. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/taskset.mdx +0 -0
  142. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/telemetry.mdx +0 -0
  143. {hud_python-0.2.10 → hud_python-0.3.0}/docs/api-reference/trajectory.mdx +0 -0
  144. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/adapter.mdx +0 -0
  145. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/agent.mdx +0 -0
  146. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/environment.mdx +0 -0
  147. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/job.mdx +0 -0
  148. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/task.mdx +0 -0
  149. {hud_python-0.2.10 → hud_python-0.3.0}/docs/concepts/trajectory.mdx +0 -0
  150. {hud_python-0.2.10 → hud_python-0.3.0}/docs/docs.json +0 -0
  151. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environment-creation.mdx +0 -0
  152. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environments/browser.mdx +0 -0
  153. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environments/custom-environments.mdx +0 -0
  154. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environments/custom.mdx +0 -0
  155. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environments/osworld-ubuntu.mdx +0 -0
  156. {hud_python-0.2.10 → hud_python-0.3.0}/docs/environments/qa.mdx +0 -0
  157. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/alignment-evaluation.mdx +0 -0
  158. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/benchmarking-agents.mdx +0 -0
  159. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/custom-os-env.mdx +0 -0
  160. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/mcp-agent-tracing.mdx +0 -0
  161. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/web-app-testing.mdx +0 -0
  162. {hud_python-0.2.10 → hud_python-0.3.0}/docs/examples/web-mocks.mdx +0 -0
  163. {hud_python-0.2.10 → hud_python-0.3.0}/docs/favicon.png +0 -0
  164. {hud_python-0.2.10 → hud_python-0.3.0}/docs/logo/hud_logo.svg +0 -0
  165. {hud_python-0.2.10 → hud_python-0.3.0}/docs/logo/hud_logo_dark.svg +0 -0
  166. {hud_python-0.2.10 → hud_python-0.3.0}/docs/quickstart.mdx +0 -0
  167. {hud_python-0.2.10 → hud_python-0.3.0}/docs/running-your-agent.mdx +0 -0
  168. {hud_python-0.2.10 → hud_python-0.3.0}/docs/task-creation.mdx +0 -0
  169. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/Dockerfile +0 -0
  170. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/pyproject.toml +0 -0
  171. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/__init__.py +0 -0
  172. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/display_adapters.py +0 -0
  173. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/emulator.py +0 -0
  174. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/evaluator.py +0 -0
  175. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/kill.py +0 -0
  176. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/main.py +0 -0
  177. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/setup.py +0 -0
  178. {hud_python-0.2.10 → hud_python-0.3.0}/environments/pokemon_controller/src/hud_controller/step.py +0 -0
  179. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/Dockerfile +0 -0
  180. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/pyproject.toml +0 -0
  181. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/__init__.py +0 -0
  182. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/evaluate/__init__.py +0 -0
  183. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/evaluate/matchers.py +0 -0
  184. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/info.py +0 -0
  185. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/setup/__init__.py +0 -0
  186. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/setup/question.py +0 -0
  187. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/step.py +0 -0
  188. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/utils/__init__.py +0 -0
  189. {hud_python-0.2.10 → hud_python-0.3.0}/environments/qa_controller/src/hud_controller/utils/state.py +0 -0
  190. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/agents_tools}/mcp_test.ipynb +0 -0
  191. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/environments}/pokemon_local.ipynb +0 -0
  192. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/environments}/pokemon_remote.ipynb +0 -0
  193. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/environments}/remote.ipynb +0 -0
  194. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/evaluations}/osworld.ipynb +0 -0
  195. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/evaluations}/sheetbench_direct_example.ipynb +0 -0
  196. {hud_python-0.2.10/examples → hud_python-0.3.0/examples/evaluations}/tasks.ipynb +0 -0
  197. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/__init__.py +0 -0
  198. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/claude/__init__.py +0 -0
  199. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/claude/adapter.py +0 -0
  200. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/claude/tests/__init__.py +0 -0
  201. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/claude/tests/test_adapter.py +0 -0
  202. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/common/__init__.py +0 -0
  203. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/common/adapter.py +0 -0
  204. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/common/tests/__init__.py +0 -0
  205. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/common/tests/test_adapter.py +0 -0
  206. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/common/types.py +0 -0
  207. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/operator/__init__.py +0 -0
  208. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/operator/adapter.py +0 -0
  209. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/operator/tests/__init__.py +0 -0
  210. {hud_python-0.2.10 → hud_python-0.3.0}/hud/adapters/operator/tests/test_adapter.py +0 -0
  211. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/__init__.py +0 -0
  212. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/base.py +0 -0
  213. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/claude.py +0 -0
  214. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/claude_plays_pokemon.py +0 -0
  215. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/langchain.py +0 -0
  216. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/misc/__init__.py +0 -0
  217. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/misc/response_agent.py +0 -0
  218. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/operator.py +0 -0
  219. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/tests/__init__.py +0 -0
  220. {hud_python-0.2.10 → hud_python-0.3.0}/hud/agent/tests/test_base.py +0 -0
  221. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/__init__.py +0 -0
  222. {hud_python-0.2.10 → hud_python-0.3.0}/hud/env/client.py +0 -0
  223. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/__init__.py +0 -0
  224. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/base.py +0 -0
  225. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/inspect.py +0 -0
  226. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/judge.py +0 -0
  227. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/match.py +0 -0
  228. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/remote.py +0 -0
  229. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/tests/__init__.py +0 -0
  230. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/tests/test_inspect.py +0 -0
  231. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/tests/test_judge.py +0 -0
  232. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/tests/test_match.py +0 -0
  233. {hud_python-0.2.10 → hud_python-0.3.0}/hud/evaluators/tests/test_remote.py +0 -0
  234. {hud_python-0.2.10 → hud_python-0.3.0}/hud/gym.py +0 -0
  235. {hud_python-0.2.10 → hud_python-0.3.0}/hud/job.py +0 -0
  236. {hud_python-0.2.10 → hud_python-0.3.0}/hud/py.typed +0 -0
  237. {hud_python-0.2.10 → hud_python-0.3.0}/hud/server/__init__.py +0 -0
  238. {hud_python-0.2.10 → hud_python-0.3.0}/hud/server/requests.py +0 -0
  239. {hud_python-0.2.10 → hud_python-0.3.0}/hud/server/tests/__init__.py +0 -0
  240. {hud_python-0.2.10 → hud_python-0.3.0}/hud/server/tests/test_requests.py +0 -0
  241. {hud_python-0.2.10 → hud_python-0.3.0}/hud/taskset.py +0 -0
  242. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/instrumentation/__init__.py +0 -0
  243. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/instrumentation/registry.py +0 -0
  244. {hud_python-0.2.10 → hud_python-0.3.0}/hud/telemetry/tests/__init__.py +0 -0
  245. {hud_python-0.2.10 → hud_python-0.3.0}/hud/trajectory.py +0 -0
  246. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/__init__.py +0 -0
  247. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/agent.py +0 -0
  248. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/common.py +0 -0
  249. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/config.py +0 -0
  250. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/misc.py +0 -0
  251. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/progress.py +0 -0
  252. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/telemetry.py +0 -0
  253. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/__init__.py +0 -0
  254. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/test_common.py +0 -0
  255. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/test_config.py +0 -0
  256. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/test_progress.py +0 -0
  257. {hud_python-0.2.10 → hud_python-0.3.0}/hud/utils/tests/test_telemetry.py +0 -0
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- python-version: ["3.10", "3.11", "3.12", "3.13"]
14
+ python-version: ["3.11", "3.12", "3.13"]
15
15
 
16
16
  steps:
17
17
  - name: Check out code
@@ -23,7 +23,20 @@ jobs:
23
23
  - name: Install Python
24
24
  run: uv python install ${{ matrix.python-version }}
25
25
 
26
+ - name: Setup virtual display
27
+ run: |
28
+ sudo apt-get update
29
+ sudo apt-get install -y xvfb
30
+ Xvfb :99 -screen 0 1920x1080x24 -ac &
31
+ sleep 3
32
+
33
+ - name: Install Playwright browsers
34
+ run: uv run --with=".[dev]" playwright install chromium
35
+
26
36
  - name: Run tests
37
+ env:
38
+ DISPLAY: :99
39
+ XAUTHORITY: /dev/null
27
40
  run: uv run --python ${{ matrix.python-version }} --with=".[dev]" pytest --rootdir=hud --cov --cov-report=''
28
41
 
29
42
  lint-ruff:
@@ -27,3 +27,5 @@ test.json
27
27
  TODO.md
28
28
 
29
29
  .coverage
30
+
31
+ *.log
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hud-python
3
- Version: 0.2.10
4
- Summary: SDK for the HUD evaluation platform.
3
+ Version: 0.3.0
4
+ Summary: SDK for the HUD platform.
5
5
  Project-URL: Homepage, https://github.com/hud-evals/hud-sdk
6
6
  Project-URL: Bug Tracker, https://github.com/hud-evals/hud-sdk/issues
7
- Project-URL: Documentation, https://hud.so
7
+ Project-URL: Documentation, https://docs.hud.so
8
8
  Author-email: HUD SDK <founders@hud.so>
9
9
  License: MIT License
10
10
 
@@ -31,11 +31,10 @@ License-File: LICENSE
31
31
  Classifier: Development Status :: 4 - Beta
32
32
  Classifier: Intended Audience :: Developers
33
33
  Classifier: Programming Language :: Python :: 3
34
- Classifier: Programming Language :: Python :: 3.10
35
34
  Classifier: Programming Language :: Python :: 3.11
36
35
  Classifier: Programming Language :: Python :: 3.12
37
36
  Classifier: Programming Language :: Python :: 3.13
38
- Requires-Python: <3.14,>=3.10
37
+ Requires-Python: <3.14,>=3.11
39
38
  Requires-Dist: aiodocker>=0.24.0
40
39
  Requires-Dist: anthropic
41
40
  Requires-Dist: dotenv>=0.9.9
@@ -43,12 +42,15 @@ Requires-Dist: httpx<1,>=0.23.0
43
42
  Requires-Dist: inspect-ai>=0.3.80
44
43
  Requires-Dist: ipykernel
45
44
  Requires-Dist: langchain
45
+ Requires-Dist: langchain-anthropic
46
46
  Requires-Dist: langchain-openai
47
- Requires-Dist: mcp
47
+ Requires-Dist: mcp-use>=1.3.7
48
+ Requires-Dist: mcp==1.12.2
48
49
  Requires-Dist: numpy
49
50
  Requires-Dist: openai
50
51
  Requires-Dist: pathspec>=0.12.1
51
52
  Requires-Dist: pillow>=11.1.0
53
+ Requires-Dist: pyautogui>=0.9.54
52
54
  Requires-Dist: pydantic-settings<3,>=2
53
55
  Requires-Dist: pydantic<3,>=2
54
56
  Requires-Dist: textdistance<5,>=4.5.0
@@ -62,6 +64,7 @@ Requires-Dist: ipython<9; extra == 'dev'
62
64
  Requires-Dist: jupyter-client; extra == 'dev'
63
65
  Requires-Dist: jupyter-core; extra == 'dev'
64
66
  Requires-Dist: openai; extra == 'dev'
67
+ Requires-Dist: playwright; extra == 'dev'
65
68
  Requires-Dist: pyright==1.1.401; extra == 'dev'
66
69
  Requires-Dist: pytest-asyncio; extra == 'dev'
67
70
  Requires-Dist: pytest-cov; extra == 'dev'
@@ -0,0 +1,163 @@
1
+ # HUD MCP Environment Requirements
2
+
3
+ Quick guide for creating HUD-compatible MCP environments.
4
+
5
+ ## Required MCP Tools
6
+
7
+ ### 1. `setup` Tool
8
+ ```python
9
+ @mcp.tool()
10
+ async def setup(config: dict) -> dict:
11
+ """Initialize environment from task.setup config (any format)."""
12
+ # Handle config however your environment needs
13
+ return {"status": "success"} # Return format is flexible
14
+ ```
15
+
16
+ ### 2. `evaluate` Tool
17
+ ```python
18
+ @mcp.tool()
19
+ async def evaluate(config: dict) -> dict:
20
+ """Evaluate task completion from task.evaluate config."""
21
+ # Your evaluation logic
22
+ return {
23
+ "reward": 1.0, # Required: 0.0-1.0 score
24
+ "done": True, # Required: completion flag
25
+ "info": {} # Optional: metadata
26
+ }
27
+ ```
28
+
29
+ ### 3. Interaction Tool(s)
30
+ At least one tool for agent interaction during task execution:
31
+
32
+ ```python
33
+ # Option A: Use HUD computer tool
34
+ from hud.tools import HudComputerTool
35
+ from hud.tools.helper import register_instance_tool
36
+
37
+ register_instance_tool(mcp, "computer", HudComputerTool())
38
+
39
+ # Option B: Custom API tool
40
+ @mcp.tool()
41
+ async def api_request(url: str, method: str = "GET", data: dict = None) -> dict:
42
+ # Your API logic
43
+ pass
44
+ ```
45
+
46
+ **Note**: `setup` and `evaluate` are **lifecycle** MCP tools that:
47
+ - Are **automatically discovered** by the MCP client (always available to framework)
48
+ - Are **filtered out** from LLM conversation (not in `allowed_tools`)
49
+ - Are **called programmatically** by the agent during task execution
50
+
51
+ Only include **interaction tools** in `allowed_tools`: `computer`, `anthropic_computer`, `api_request`, etc.
52
+
53
+ ## Config Flexibility
54
+
55
+ Task configs can be **any format**:
56
+ ```python
57
+ task.setup = {"function": "reset", "args": {}}
58
+ task.setup = {"id": "task_123"}
59
+ task.setup = {"name": "problem_name"}
60
+ task.setup = "simple_string"
61
+ task.setup = ["step1", "step2"]
62
+ # Your environment decides what formats to support
63
+ ```
64
+
65
+ ## Minimal Example
66
+
67
+ ```python
68
+ from fastmcp import FastMCP
69
+ from hud.tools import HudComputerTool
70
+ from hud.tools.helper import register_instance_tool
71
+
72
+ mcp = FastMCP("My Environment")
73
+
74
+ @mcp.tool()
75
+ async def setup(config: dict) -> dict:
76
+ return {"status": "success"}
77
+
78
+ @mcp.tool()
79
+ async def evaluate(config: dict) -> dict:
80
+ return {"reward": 1.0, "done": True, "info": {}}
81
+
82
+ @mcp.initialize()
83
+ async def init():
84
+ register_instance_tool(mcp, "computer", HudComputerTool())
85
+
86
+ if __name__ == "__main__":
87
+ mcp.run()
88
+ ```
89
+
90
+ ## Testing Your Environment
91
+
92
+ ### Unified Agent Interface
93
+
94
+ ```python
95
+ import asyncio
96
+ from hud.mcp_agent import ClaudeMCPAgent
97
+ from hud import Task
98
+ from mcp_use import MCPClient
99
+
100
+ async def test_environment():
101
+ # Connect to your environment
102
+ config = {"mcpServers": {"env": {"command": "python", "args": ["my_env.py"]}}}
103
+ client = MCPClient.from_dict(config)
104
+
105
+ # Create agent (only specify interaction tools)
106
+ agent = ClaudeMCPAgent(
107
+ client=client,
108
+ model="claude-sonnet-4-20250514",
109
+ allowed_tools=["computer", "api_request"] # Interaction tools only
110
+ )
111
+
112
+ # Simple query
113
+ result = await agent.run("Take a screenshot and describe what you see")
114
+ print(f"Query result: {result}")
115
+
116
+ # Full task with lifecycle
117
+ task = Task(
118
+ prompt="Complete the todo app workflow",
119
+ setup={"function": "todo_seed", "args": {"num_items": 3}},
120
+ evaluate={"function": "todo_completed", "args": {"expected_count": 1}}
121
+ )
122
+
123
+ eval_result = await agent.run(task)
124
+ print(f"Task result: {eval_result}")
125
+ # Returns: {"reward": 1.0, "done": True, "info": {...}}
126
+
127
+ await client.close_all_sessions()
128
+
129
+ # Run the test
130
+ asyncio.run(test_environment())
131
+ ```
132
+
133
+ ### Direct MCP Tool Testing
134
+
135
+ ```python
136
+ from mcp_use import MCPClient
137
+
138
+ # Test individual tools
139
+ config = {"mcpServers": {"env": {"command": "python", "args": ["my_env.py"]}}}
140
+ client = MCPClient.from_dict(config)
141
+ session = await client.create_session("env")
142
+
143
+ # Test setup/evaluate tools directly
144
+ setup_result = await session.connector.call_tool("setup", {"function": "test_setup"})
145
+ eval_result = await session.connector.call_tool("evaluate", {"function": "test_eval"})
146
+ ```
147
+
148
+ ## Key Features
149
+
150
+ ✨ **Unified Interface**: Single `agent.run()` method handles both simple queries and full task lifecycle
151
+ 🔄 **Automatic Lifecycle**: Setup → Execute → Evaluate phases managed automatically
152
+ 📋 **Flexible Config**: Support any setup/evaluate config format your environment needs
153
+ 🔧 **Easy Integration**: Import HUD tools with `register_instance_tool()`
154
+ 🛡️ **Smart Tool Filtering**: Lifecycle tools auto-discovered but hidden from LLM conversation
155
+
156
+ ## Examples
157
+
158
+ ### Environment Examples
159
+ - [`simple_browser/`](./simple_browser/) - Computer tool + GUI automation
160
+ - [`qa_controller/`](./qa_controller/) - Text-based environment
161
+
162
+ ### Usage Examples
163
+ - [`simple_task_example.py`](../examples/agents_tools/simple_task_example.py) - Complete demo with simple_browser environment
@@ -0,0 +1,52 @@
1
+ # Git
2
+ .git
3
+ .gitignore
4
+
5
+ # Node
6
+ app/frontend/node_modules
7
+ app/frontend/.next
8
+ app/frontend/build
9
+ app/frontend/dist
10
+ apps/*/frontend/node_modules
11
+ apps/*/frontend/.next
12
+ apps/*/frontend/build
13
+ apps/*/frontend/dist
14
+ *.log
15
+
16
+ # Python
17
+ __pycache__
18
+ *.pyc
19
+ *.pyo
20
+ *.pyd
21
+ .Python
22
+ *.egg-info
23
+ .pytest_cache
24
+ .mypy_cache
25
+ .coverage
26
+ .venv
27
+ venv
28
+ env
29
+ apps/*/.venv
30
+ apps/*/backend/.venv
31
+ apps/*/backend/venv
32
+
33
+ # Database
34
+ app/backend/*.db
35
+ app/backend/*.sqlite
36
+ apps/*/backend/*.db
37
+ apps/*/backend/*.sqlite
38
+
39
+ # IDE
40
+ .vscode
41
+ .idea
42
+ *.swp
43
+ *.swo
44
+
45
+ # OS
46
+ .DS_Store
47
+ Thumbs.db
48
+
49
+ # Documentation
50
+ *.md
51
+ !app/README.md
52
+ !launch/README.md
@@ -0,0 +1,100 @@
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Testing
7
+ coverage/
8
+ .coverage
9
+ .pytest_cache/
10
+ htmlcov/
11
+
12
+ # Next.js
13
+ .next/
14
+ out/
15
+ build/
16
+ *.tsbuildinfo
17
+ next-env.d.ts
18
+
19
+ # Production
20
+ dist/
21
+
22
+ # Misc
23
+ .DS_Store
24
+ *.pem
25
+ Thumbs.db
26
+
27
+ # Debug
28
+ npm-debug.log*
29
+ yarn-debug.log*
30
+ yarn-error.log*
31
+ .pnpm-debug.log*
32
+
33
+ # Local env files
34
+ .env
35
+ .env.local
36
+ .env.development.local
37
+ .env.test.local
38
+ .env.production.local
39
+
40
+ # Vercel
41
+ .vercel
42
+
43
+ # TypeScript
44
+ *.tsbuildinfo
45
+
46
+ # Python
47
+ __pycache__/
48
+ *.py[cod]
49
+ *$py.class
50
+ *.so
51
+ .Python
52
+ env/
53
+ venv/
54
+ .venv/
55
+ ENV/
56
+ env.bak/
57
+ venv.bak/
58
+ *.egg-info/
59
+ .installed.cfg
60
+ *.egg
61
+ MANIFEST
62
+
63
+ # uv
64
+ .venv/
65
+ uv.lock
66
+
67
+ # Database
68
+ *.db
69
+ *.sqlite
70
+ *.sqlite3
71
+ app.db
72
+
73
+ # IDEs
74
+ .vscode/
75
+ .idea/
76
+ *.swp
77
+ *.swo
78
+ *~
79
+ .project
80
+ .classpath
81
+ .c9/
82
+ *.launch
83
+ .settings/
84
+ *.sublime-workspace
85
+
86
+ # OS
87
+ .DS_Store
88
+ .DS_Store?
89
+ ._*
90
+ .Spotlight-V100
91
+ .Trashes
92
+ ehthumbs.db
93
+ Thumbs.db
94
+
95
+ # Logs
96
+ logs/
97
+ *.log
98
+
99
+ # Docker
100
+ .dockerignore.local
@@ -0,0 +1,159 @@
1
+ # Deployment Guide for HUD Browser Environment
2
+
3
+ This guide explains how to build and deploy the simple browser environment for use with the HUD MCP server.
4
+
5
+ ## Quick Start
6
+
7
+ To use this environment with the HUD MCP server, configure your MCP client:
8
+
9
+ ```python
10
+ config = {
11
+ "mcpServers": {
12
+ "browser": {
13
+ "url": "https://mcp.hud.so/api/v3/mcp",
14
+ "headers": {
15
+ "Authorization": f"Bearer {HUD_API_KEY}",
16
+ "Mcp-Image": "your-username/hud-browser:latest" # Your published image
17
+ }
18
+ }
19
+ }
20
+ }
21
+ ```
22
+
23
+ ## What's in the Image
24
+
25
+ The `hud-browser` image contains:
26
+ - **Chromium Browser** with Playwright for automation
27
+ - **MCP Server** running in stdio mode with computer tools
28
+ - **VNC Server** for remote viewing (port 8080)
29
+ - **Pre-built Web Apps** (e.g., todo app with Next.js frontend and FastAPI backend)
30
+
31
+ ## Building and Publishing the Image
32
+
33
+ ### Option 1: Docker Hub (Public/Private)
34
+
35
+ ```bash
36
+ # Build the image
37
+ docker build -t your-username/hud-browser:latest environments/simple_browser/
38
+
39
+ # Push to Docker Hub
40
+ docker login
41
+ docker push your-username/hud-browser:latest
42
+
43
+ # Use in MCP client
44
+ "Mcp-Image": "your-username/hud-browser:latest"
45
+ ```
46
+
47
+ ### Option 2: GitHub Container Registry
48
+
49
+ ```bash
50
+ # Build and tag
51
+ docker build -t ghcr.io/your-org/hud-browser:latest environments/simple_browser/
52
+
53
+ # Login and push
54
+ echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
55
+ docker push ghcr.io/your-org/hud-browser:latest
56
+
57
+ # Use in MCP client
58
+ "Mcp-Image": "ghcr.io/your-org/hud-browser:latest"
59
+ ```
60
+
61
+ ### Option 3: Google Container Registry (GCR)
62
+
63
+ ```bash
64
+ # Build and tag
65
+ docker build -t gcr.io/your-project/hud-browser:latest environments/simple_browser/
66
+
67
+ # Configure auth and push
68
+ gcloud auth configure-docker
69
+ docker push gcr.io/your-project/hud-browser:latest
70
+
71
+ # Use in MCP client
72
+ "Mcp-Image": "gcr.io/your-project/hud-browser:latest"
73
+ ```
74
+
75
+ ### Option 4: AWS Elastic Container Registry (ECR)
76
+
77
+ ```bash
78
+ # Build the image
79
+ docker build -t hud-browser:latest environments/simple_browser/
80
+
81
+ # Tag for ECR
82
+ docker tag hud-browser:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/hud-browser:latest
83
+
84
+ # Login and push
85
+ aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
86
+ docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/hud-browser:latest
87
+
88
+ # Use in MCP client
89
+ "Mcp-Image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/hud-browser:latest"
90
+ ```
91
+
92
+ ### Option 5: Private Registry
93
+
94
+ ```bash
95
+ # Build and tag for your registry
96
+ docker build -t registry.company.com/hud-browser:latest environments/simple_browser/
97
+
98
+ # Push to private registry
99
+ docker push registry.company.com/hud-browser:latest
100
+
101
+ # Use in MCP client
102
+ "Mcp-Image": "registry.company.com/hud-browser:latest"
103
+ ```
104
+
105
+ ## Configuring the Environment
106
+
107
+ Environment variables are passed through headers with the `Env-` prefix. The header name is transformed to create the environment variable:
108
+ - The `Env-` prefix is removed
109
+ - Dashes are converted to underscores
110
+ - The name is converted to uppercase
111
+
112
+ For example: `Env-launch-apps` → `LAUNCH_APPS`
113
+
114
+ ### Available Environment Variables
115
+
116
+ - `LAUNCH_APPS` - Comma-separated list of apps to launch (default: none)
117
+ - `BROWSER_URL` - URL to navigate browser to (default: https://google.com)
118
+ - `WAIT_FOR_APPS` - Wait for apps before browser navigation (default: true)
119
+ - `FRONTEND_PORT_START` - Starting port for frontend services (default: 3000)
120
+ - `BACKEND_PORT_START` - Starting port for backend services (default: 5000)
121
+ - `MCP_TRANSPORT` - MCP server transport mode: stdio or streamable-http (default: stdio)
122
+
123
+ ### Example: Launch with Todo App
124
+
125
+ ```python
126
+ config = {
127
+ "mcpServers": {
128
+ "browser": {
129
+ "url": "https://mcp.hud.so/api/v3/mcp",
130
+ "headers": {
131
+ "Authorization": f"Bearer {HUD_API_KEY}",
132
+ "Mcp-Image": "your-username/hud-browser:latest",
133
+ "Env-launch-apps": "todo",
134
+ "Env-browser-url": "http://localhost:3000"
135
+ }
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Example: Multiple Apps with Custom Ports
142
+
143
+ ```python
144
+ config = {
145
+ "mcpServers": {
146
+ "browser": {
147
+ "url": "https://mcp.hud.so/api/v3/mcp",
148
+ "headers": {
149
+ "Authorization": f"Bearer {HUD_API_KEY}",
150
+ "Mcp-Image": "your-username/hud-browser:latest",
151
+ "Env-launch-apps": "todo,calendar",
152
+ "Env-frontend-port-start": "3000",
153
+ "Env-backend-port-start": "5000",
154
+ "Env-wait-for-apps": "true"
155
+ }
156
+ }
157
+ }
158
+ }
159
+ ```
@@ -0,0 +1,38 @@
1
+ FROM hudpython/novnc-base:latest
2
+ # Install package
3
+ WORKDIR /app
4
+ COPY pyproject.toml .
5
+ COPY src/ ./src/
6
+ RUN uv pip install --system --break-system-packages -e .
7
+
8
+ # Copy apps
9
+ COPY apps/ /app/apps/
10
+
11
+ # Make launch scripts executable
12
+ RUN find /app/apps -name "launch.py" -type f -exec chmod +x {} \;
13
+
14
+ # Pre-install npm dependencies for all frontend apps
15
+ RUN for app in /app/apps/*/frontend; do \
16
+ if [ -f "$app/package.json" ]; then \
17
+ echo "Installing npm dependencies for $app"; \
18
+ cd "$app" && npm install; \
19
+ echo "Building Next.js app in $app"; \
20
+ npm run build || echo "Build failed for $app (might not be Next.js)"; \
21
+ cd -; \
22
+ fi \
23
+ done
24
+
25
+ # Set defaults
26
+ ENV MCP_TRANSPORT="stdio"
27
+ ENV HUD_LOG_STREAM="stderr"
28
+ ENV PYTHONUNBUFFERED="1"
29
+
30
+ # Expose all the ports we need
31
+ EXPOSE 8080 8040-8050 3000-3010 5000-5010
32
+
33
+ # Copy and use start script
34
+ COPY start.sh /app/start.sh
35
+ RUN chmod +x /app/start.sh
36
+
37
+ # Run via start script to ensure X11 is ready
38
+ CMD ["/app/start.sh"]