deepagents-cli 0.0.36__tar.gz → 0.0.37__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 (193) hide show
  1. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/.gitignore +3 -0
  2. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/CHANGELOG.md +13 -0
  3. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/PKG-INFO +2 -2
  4. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_version.py +1 -1
  5. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/app.py +1 -1
  6. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/config.py +3 -1
  7. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/__init__.py +3 -0
  8. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/bundler.py +34 -21
  9. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/commands.py +61 -48
  10. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/config.py +60 -30
  11. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/templates.py +20 -43
  12. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/sandbox_factory.py +5 -2
  13. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/model_config.py +2 -0
  14. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/pyproject.toml +2 -2
  15. deepagents_cli-0.0.37/tests/unit_tests/deploy/test_bundler.py +245 -0
  16. deepagents_cli-0.0.37/tests/unit_tests/deploy/test_commands.py +75 -0
  17. deepagents_cli-0.0.37/tests/unit_tests/deploy/test_config.py +302 -0
  18. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_config.py +4 -4
  19. deepagents_cli-0.0.37/tests/unit_tests/tools/__init__.py +0 -0
  20. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/uv.lock +2 -2
  21. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/DEV.md +0 -0
  22. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/Makefile +0 -0
  23. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/README.md +0 -0
  24. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/THREAT_MODEL.md +0 -0
  25. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/__init__.py +0 -0
  26. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/__main__.py +0 -0
  27. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_ask_user_types.py +0 -0
  28. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_cli_context.py +0 -0
  29. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_debug.py +0 -0
  30. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_env_vars.py +0 -0
  31. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_server_config.py +0 -0
  32. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_session_stats.py +0 -0
  33. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_testing_models.py +0 -0
  34. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/agent.py +0 -0
  35. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/app.tcss +0 -0
  36. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/ask_user.py +0 -0
  37. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/__init__.py +0 -0
  38. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
  39. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
  40. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  41. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  42. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/clipboard.py +0 -0
  43. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/command_registry.py +0 -0
  44. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/configurable_model.py +0 -0
  45. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/default_agent_prompt.md +0 -0
  46. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/editor.py +0 -0
  47. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/file_ops.py +0 -0
  48. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/formatting.py +0 -0
  49. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/hooks.py +0 -0
  50. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/input.py +0 -0
  51. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/__init__.py +0 -0
  52. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/sandbox_provider.py +0 -0
  53. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/local_context.py +0 -0
  54. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/main.py +0 -0
  55. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/mcp_tools.py +0 -0
  56. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/mcp_trust.py +0 -0
  57. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/media_utils.py +0 -0
  58. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/non_interactive.py +0 -0
  59. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/offload.py +0 -0
  60. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/output.py +0 -0
  61. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/project_utils.py +0 -0
  62. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/py.typed +0 -0
  63. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/remote_client.py +0 -0
  64. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server.py +0 -0
  65. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server_graph.py +0 -0
  66. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server_manager.py +0 -0
  67. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/sessions.py +0 -0
  68. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/__init__.py +0 -0
  69. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/commands.py +0 -0
  70. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/invocation.py +0 -0
  71. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/load.py +0 -0
  72. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/subagents.py +0 -0
  73. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/system_prompt.md +0 -0
  74. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/textual_adapter.py +0 -0
  75. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/theme.py +0 -0
  76. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/token_state.py +0 -0
  77. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/tool_display.py +0 -0
  78. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/tools.py +0 -0
  79. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/ui.py +0 -0
  80. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/unicode_security.py +0 -0
  81. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/update_check.py +0 -0
  82. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/__init__.py +0 -0
  83. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/_links.py +0 -0
  84. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/approval.py +0 -0
  85. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/ask_user.py +0 -0
  86. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/autocomplete.py +0 -0
  87. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/chat_input.py +0 -0
  88. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/diff.py +0 -0
  89. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/history.py +0 -0
  90. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/loading.py +0 -0
  91. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/mcp_viewer.py +0 -0
  92. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/message_store.py +0 -0
  93. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/messages.py +0 -0
  94. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/model_selector.py +0 -0
  95. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/notification_settings.py +0 -0
  96. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/status.py +0 -0
  97. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/theme_selector.py +0 -0
  98. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/thread_selector.py +0 -0
  99. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/tool_renderers.py +0 -0
  100. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/tool_widgets.py +0 -0
  101. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/welcome.py +0 -0
  102. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/arxiv-search/SKILL.md +0 -0
  103. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  104. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/langgraph-docs/SKILL.md +0 -0
  105. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/SKILL.md +0 -0
  106. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  107. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  108. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/web-research/SKILL.md +0 -0
  109. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/images/cli.png +0 -0
  110. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/check_imports.py +0 -0
  111. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/debug_server.sh +0 -0
  112. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/install.sh +0 -0
  113. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/README.md +0 -0
  114. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/__init__.py +0 -0
  115. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/__init__.py +0 -0
  116. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
  117. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  118. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/conftest.py +0 -0
  119. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_acp_mode.py +0 -0
  120. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_compact_resume.py +0 -0
  121. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_sandbox_factory.py +0 -0
  122. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_sandbox_operations.py +0 -0
  123. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/__init__.py +0 -0
  124. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/conftest.py +0 -0
  125. {deepagents_cli-0.0.36/tests/unit_tests/tools → deepagents_cli-0.0.37/tests/unit_tests/deploy}/__init__.py +0 -0
  126. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/__init__.py +0 -0
  127. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_commands.py +0 -0
  128. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_load.py +0 -0
  129. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_skills_json.py +0 -0
  130. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_agent.py +0 -0
  131. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_agent_friendly.py +0 -0
  132. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_app.py +0 -0
  133. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_approval.py +0 -0
  134. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_args.py +0 -0
  135. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ask_user.py +0 -0
  136. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  137. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_autocomplete.py +0 -0
  138. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_charset.py +0 -0
  139. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_chat_input.py +0 -0
  140. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_command_registry.py +0 -0
  141. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_compact_tool.py +0 -0
  142. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_configurable_model.py +0 -0
  143. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_debug.py +0 -0
  144. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_editor.py +0 -0
  145. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_end_to_end.py +0 -0
  146. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_env_vars.py +0 -0
  147. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_exception_handling.py +0 -0
  148. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_file_ops.py +0 -0
  149. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_history.py +0 -0
  150. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_hooks.py +0 -0
  151. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_imports.py +0 -0
  152. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_input_parsing.py +0 -0
  153. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_links.py +0 -0
  154. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_loading.py +0 -0
  155. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_local_context.py +0 -0
  156. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main.py +0 -0
  157. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main_acp_mode.py +0 -0
  158. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main_args.py +0 -0
  159. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_tools.py +0 -0
  160. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_trust.py +0 -0
  161. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_viewer.py +0 -0
  162. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_media_utils.py +0 -0
  163. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_message_store.py +0 -0
  164. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_messages.py +0 -0
  165. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_config.py +0 -0
  166. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_selector.py +0 -0
  167. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_switch.py +0 -0
  168. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_non_interactive.py +0 -0
  169. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_offload.py +0 -0
  170. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_output.py +0 -0
  171. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_reload.py +0 -0
  172. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_remote_client.py +0 -0
  173. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_sandbox_factory.py +0 -0
  174. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server.py +0 -0
  175. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_config.py +0 -0
  176. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_graph.py +0 -0
  177. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_helpers.py +0 -0
  178. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_manager.py +0 -0
  179. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_sessions.py +0 -0
  180. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_shell_allow_list.py +0 -0
  181. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_skill_invocation.py +0 -0
  182. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_status.py +0 -0
  183. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_subagents.py +0 -0
  184. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_textual_adapter.py +0 -0
  185. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_theme.py +0 -0
  186. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_thread_selector.py +0 -0
  187. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_token_tracker.py +0 -0
  188. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ui.py +0 -0
  189. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_unicode_security.py +0 -0
  190. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_update_check.py +0 -0
  191. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_version.py +0 -0
  192. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_welcome.py +0 -0
  193. {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/tools/test_fetch_url.py +0 -0
@@ -212,6 +212,9 @@ __marimo__/
212
212
  #claude
213
213
  .claude
214
214
 
215
+ # Harbor local job output
216
+ jobs/
217
+
215
218
  .idea
216
219
  TEXTUAL_REFACTOR_PLAN.md
217
220
  libs/cli/TEXTUAL_PROGRESS.md
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.37](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.36...deepagents-cli==0.0.37) (2026-04-10)
4
+
5
+ ### Features
6
+
7
+ * Permissions for `deepagents deploy` ([#2651](https://github.com/langchain-ai/deepagents/issues/2651)) ([5d93b73](https://github.com/langchain-ai/deepagents/commit/5d93b736af6ffb165f33569233d533ced95a6943))
8
+
9
+ ### Bug Fixes
10
+
11
+ * Add missing model provider deps to `deepagents deploy` bundler [closes [#2647](https://github.com/langchain-ai/deepagents/issues/2647)] ([#2660](https://github.com/langchain-ai/deepagents/issues/2660)) ([b710a69](https://github.com/langchain-ai/deepagents/commit/b710a69b12e49479045eaa54dfb709326473500b))
12
+ * `AGENTS.md` in system prompt twice ([#2652](https://github.com/langchain-ai/deepagents/issues/2652)) ([9052be9](https://github.com/langchain-ai/deepagents/commit/9052be98d9f4ef9b11a88c9b1df3fae5e5ac666c))
13
+ * Harden `deepagents deploy` config parsing and add unit tests ([#2636](https://github.com/langchain-ai/deepagents/issues/2636)) ([0469d14](https://github.com/langchain-ai/deepagents/commit/0469d1429d129e604fc1b622263923162f719314))
14
+ * Load `deepagents deploy` project `.env` before deploy/dev config validation ([#2644](https://github.com/langchain-ai/deepagents/issues/2644)) ([8299091](https://github.com/langchain-ai/deepagents/commit/829909166606f8a9d9571b00da725845bad08da7))
15
+
3
16
  ## [0.0.36](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.35...deepagents-cli==0.0.36) (2026-04-09)
4
17
 
5
18
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents-cli
3
- Version: 0.0.36
3
+ Version: 0.0.37
4
4
  Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
5
5
  Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
6
6
  Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
@@ -27,7 +27,7 @@ Classifier: Topic :: Terminals
27
27
  Requires-Python: <4.0,>=3.11
28
28
  Requires-Dist: aiosqlite<1.0.0,>=0.19.0
29
29
  Requires-Dist: deepagents-acp>=0.0.4
30
- Requires-Dist: deepagents==0.5.1
30
+ Requires-Dist: deepagents==0.5.2
31
31
  Requires-Dist: httpx<1.0.0,>=0.28.1
32
32
  Requires-Dist: langchain-anthropic<2.0.0,>=1.4.0
33
33
  Requires-Dist: langchain-google-genai<5.0.0,>=4.2.1
@@ -1,6 +1,6 @@
1
1
  """Version information and lightweight constants for `deepagents-cli`."""
2
2
 
3
- __version__ = "0.0.36" # x-release-please-version
3
+ __version__ = "0.0.37" # x-release-please-version
4
4
 
5
5
  DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/cli"
6
6
  """URL for `deepagents-cli` documentation."""
@@ -1478,7 +1478,7 @@ class DeepAgentsApp(App):
1478
1478
  cmd = upgrade_command()
1479
1479
  self.notify(
1480
1480
  f"Update available: v{latest} (current: v{cli_version}). "
1481
- f"Run: {cmd}\n"
1481
+ f"Run: {cmd}\n\n"
1482
1482
  f"Enable auto-updates: /auto-update",
1483
1483
  severity="information",
1484
1484
  timeout=15,
@@ -1937,7 +1937,9 @@ def _get_provider_kwargs(
1937
1937
  result["api_key"] = api_key
1938
1938
 
1939
1939
  if provider == "openrouter":
1940
- from deepagents._models import check_openrouter_version # noqa: PLC2701
1940
+ from deepagents.profiles._openrouter import (
1941
+ check_openrouter_version, # noqa: PLC2701
1942
+ )
1941
1943
 
1942
1944
  check_openrouter_version()
1943
1945
  _apply_openrouter_defaults(result)
@@ -6,8 +6,11 @@ from deepagents_cli.deploy.commands import (
6
6
  execute_init_command,
7
7
  setup_deploy_parsers,
8
8
  )
9
+ from deepagents_cli.deploy.config import SandboxProvider, SandboxScope
9
10
 
10
11
  __all__ = [
12
+ "SandboxProvider",
13
+ "SandboxScope",
11
14
  "execute_deploy_command",
12
15
  "execute_dev_command",
13
16
  "execute_init_command",
@@ -3,11 +3,12 @@
3
3
  Reads the canonical project layout:
4
4
 
5
5
  ```txt
6
- src/
7
- AGENTS.md # required — system prompt + seeded memory
8
- skills/ # optionalauto-seeded into skills namespace
9
- mcp.json # optional — HTTP/SSE MCP servers
10
- deepagents.toml
6
+ <project>/
7
+ deepagents.toml # required — agent + sandbox config
8
+ AGENTS.md # requiredsystem prompt + seeded memory
9
+ .env # optional — environment variables
10
+ mcp.json # optional — HTTP/SSE MCP servers
11
+ skills/ # optional — auto-seeded into skills namespace
11
12
  ```
12
13
 
13
14
  ...and writes everything `langgraph deploy` needs to a build directory.
@@ -35,13 +36,22 @@ from deepagents_cli.deploy.templates import (
35
36
 
36
37
  logger = logging.getLogger(__name__)
37
38
 
38
- _MODEL_PROVIDER_DEPS = {
39
+ _MODEL_PROVIDER_DEPS: dict[str, str] = {
39
40
  "anthropic": "langchain-anthropic",
40
- "openai": "langchain-openai",
41
+ "azure_openai": "langchain-openai",
42
+ "baseten": "langchain-baseten",
43
+ "cohere": "langchain-cohere",
44
+ "deepseek": "langchain-deepseek",
45
+ "fireworks": "langchain-fireworks",
41
46
  "google_genai": "langchain-google-genai",
42
47
  "google_vertexai": "langchain-google-vertexai",
43
48
  "groq": "langchain-groq",
44
49
  "mistralai": "langchain-mistralai",
50
+ "nvidia": "langchain-nvidia-ai-endpoints",
51
+ "openai": "langchain-openai",
52
+ "openrouter": "langchain-openrouter",
53
+ "perplexity": "langchain-perplexity",
54
+ "xai": "langchain-xai",
45
55
  }
46
56
  """Dependencies inferred from a provider: prefix on the model string."""
47
57
 
@@ -76,8 +86,8 @@ def bundle(
76
86
  shutil.copy2(project_root / MCP_FILENAME, build_dir / "_mcp.json")
77
87
  logger.info("Copied %s → _mcp.json", MCP_FILENAME)
78
88
 
79
- # 3b. Copy .env from the project root if present (i.e. alongside
80
- # deepagents.toml inside ``src/``). The bundler skips .env when
89
+ # 3b. Copy .env from the project root if present (alongside
90
+ # deepagents.toml). The bundler skips .env when
81
91
  # building the seed payload so secrets never land in _seed.json.
82
92
  env_src = project_root / ".env"
83
93
  env_present = env_src.is_file()
@@ -87,7 +97,7 @@ def bundle(
87
97
 
88
98
  # 4. Render deploy_graph.py.
89
99
  (build_dir / "deploy_graph.py").write_text(
90
- _render_deploy_graph(config, system_prompt, mcp_present=mcp_present),
100
+ _render_deploy_graph(config, mcp_present=mcp_present),
91
101
  encoding="utf-8",
92
102
  )
93
103
  logger.info("Generated deploy_graph.py")
@@ -118,17 +128,18 @@ def _build_seed(
118
128
 
119
129
  ```txt
120
130
  {
121
- "memories": { "AGENTS.md": "..." },
122
- "skills": { "<skill>/SKILL.md": "...", ... }
131
+ "memories": { "/AGENTS.md": "..." },
132
+ "skills": { "/<skill>/SKILL.md": "...", ... }
123
133
  }
124
134
  ```
125
135
 
126
- `memories` always contains `AGENTS.md` — the agent reads it at runtime
127
- via `/memories/AGENTS.md`. Writes and edits to that path are blocked
128
- by `ReadOnlyStoreBackend` in the generated graph.
136
+ `memories` always contains `/AGENTS.md` — the middleware loads it at
137
+ startup via `/memories/AGENTS.md`. Agent reads of `/memories/` and
138
+ `/skills/` are denied by `FilesystemPermission` rules.
129
139
 
130
- `skills` walks `src/skills/` if present. Keys are paths relative to the
131
- skills dir; the runtime namespace handles the scoping.
140
+ `skills` walks `skills/` if present. Keys are paths relative to the
141
+ skills dir with a leading slash; the runtime namespace handles the
142
+ scoping.
132
143
  """
133
144
  # Keys must match what CompositeBackend passes to the mounted
134
145
  # StoreBackend after stripping the route prefix: for a read of
@@ -149,7 +160,6 @@ def _build_seed(
149
160
 
150
161
  def _render_deploy_graph(
151
162
  config: DeployConfig,
152
- system_prompt: str,
153
163
  *,
154
164
  mcp_present: bool,
155
165
  ) -> str:
@@ -169,7 +179,6 @@ def _render_deploy_graph(
169
179
 
170
180
  return DEPLOY_GRAPH_TEMPLATE.format(
171
181
  model=config.agent.model,
172
- system_prompt=system_prompt,
173
182
  sandbox_template=config.sandbox.template,
174
183
  sandbox_image=config.sandbox.image,
175
184
  sandbox_scope=config.sandbox.scope,
@@ -231,8 +240,12 @@ def print_bundle_summary(config: DeployConfig, build_dir: Path) -> None:
231
240
  if seed_path.exists():
232
241
  try:
233
242
  seed = json.loads(seed_path.read_text(encoding="utf-8"))
234
- except Exception:
235
- pass
243
+ except (json.JSONDecodeError, OSError) as exc:
244
+ logger.warning(
245
+ "Failed to parse %s; summary may be incomplete: %s",
246
+ seed_path,
247
+ exc,
248
+ )
236
249
 
237
250
  print(f"\n Agent: {config.agent.name}")
238
251
  print(f" Model: {config.agent.model}")
@@ -1,11 +1,6 @@
1
- """CLI commands for `deepagents deploy`.
1
+ """CLI commands for `deepagents init`, `dev`, and `deploy`.
2
2
 
3
- Registered with the CLI via `setup_deploy_parser` in `main.py`.
4
-
5
- Commands:
6
- - `deepagents deploy` — Bundle and deploy to LangGraph Platform
7
- - `deepagents deploy --dry-run` — Show what would be generated
8
- - `deepagents init [NAME]` — Scaffold a new deploy project folder
3
+ Registered with the CLI via `setup_deploy_parsers` in `main.py`.
9
4
  """
10
5
 
11
6
  from __future__ import annotations
@@ -70,7 +65,7 @@ def setup_deploy_parsers(
70
65
  "--config",
71
66
  type=str,
72
67
  default=None,
73
- help="Path to deepagents.toml (default: auto-discovered from cwd upward)",
68
+ help="Path to deepagents.toml (default: auto-discovered from cwd)",
74
69
  )
75
70
  dev_parser.add_argument(
76
71
  "--port",
@@ -100,7 +95,7 @@ def setup_deploy_parsers(
100
95
  "--config",
101
96
  type=str,
102
97
  default=None,
103
- help="Path to deepagents.toml (default: auto-discovered from cwd upward)",
98
+ help="Path to deepagents.toml (default: auto-discovered from cwd)",
104
99
  )
105
100
  deploy_parser.add_argument(
106
101
  "--dry-run",
@@ -197,14 +192,16 @@ def _init_project(*, name: str, force: bool = False) -> None:
197
192
  ]
198
193
 
199
194
  for filename, content in files:
200
- (project_dir / filename).write_text(content)
195
+ (project_dir / filename).write_text(content, encoding="utf-8")
201
196
 
202
197
  # Create skills/ directory with a starter skill.
203
198
  skills_dir = project_dir / SKILLS_DIRNAME
204
199
  skills_dir.mkdir(exist_ok=True)
205
200
  starter_skill_dir = skills_dir / STARTER_SKILL_NAME
206
201
  starter_skill_dir.mkdir(exist_ok=True)
207
- (starter_skill_dir / "SKILL.md").write_text(generate_starter_skill_md())
202
+ (starter_skill_dir / "SKILL.md").write_text(
203
+ generate_starter_skill_md(), encoding="utf-8"
204
+ )
208
205
 
209
206
  print(f"Created {name}/ with:")
210
207
  for filename, _ in files:
@@ -227,6 +224,7 @@ def _deploy(
227
224
  config_path: Path to config file, or `None` for default.
228
225
  dry_run: If `True`, generate artifacts but don't deploy.
229
226
  """
227
+ from deepagents_cli.config import _load_dotenv
230
228
  from deepagents_cli.deploy.bundler import bundle, print_bundle_summary
231
229
  from deepagents_cli.deploy.config import (
232
230
  DEFAULT_CONFIG_FILENAME,
@@ -242,6 +240,11 @@ def _deploy(
242
240
  cfg_path = discovered or Path.cwd() / DEFAULT_CONFIG_FILENAME
243
241
 
244
242
  project_root = cfg_path.parent
243
+ # Ensure the project .env is loaded into os.environ before validation.
244
+ # The main CLI bootstrap loads .env lazily (on first `settings` access),
245
+ # but deploy/dev commands may never touch `settings`, so the project
246
+ # .env would be missing when _validate_model_credentials checks os.environ.
247
+ _load_dotenv(start_path=project_root)
245
248
 
246
249
  # Load and validate config
247
250
  try:
@@ -262,10 +265,7 @@ def _deploy(
262
265
  raise SystemExit(1)
263
266
 
264
267
  # Bundle
265
- if dry_run:
266
- build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
267
- else:
268
- build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
268
+ build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
269
269
 
270
270
  try:
271
271
  bundle(config, project_root, build_dir)
@@ -276,14 +276,13 @@ def _deploy(
276
276
  print(f"Inspect the build directory: {build_dir}")
277
277
  return
278
278
 
279
- # Deploy via langgraph CLI
279
+ # Deploy via langgraph CLI.
280
280
  _run_langgraph_deploy(build_dir, name=config.agent.name)
281
+ finally:
282
+ if not dry_run:
283
+ import shutil
281
284
 
282
- except Exception:
283
- if dry_run:
284
- # Keep build dir for inspection on dry run
285
- raise
286
- raise
285
+ shutil.rmtree(build_dir, ignore_errors=True)
287
286
 
288
287
 
289
288
  def _dev(
@@ -298,7 +297,7 @@ def _dev(
298
297
  served locally instead of pushed to LangGraph Platform. Hot-reloading
299
298
  is provided by `langgraph dev` itself watching the build directory;
300
299
  edits to the source project (`deepagents.toml`, skills, `AGENTS.md`)
301
- require re-running `deepagents deploy dev` to re-bundle.
300
+ require re-running `deepagents dev` to re-bundle.
302
301
 
303
302
  Args:
304
303
  config_path: Path to `deepagents.toml`, or `None` for default.
@@ -309,6 +308,7 @@ def _dev(
309
308
  """
310
309
  import shutil
311
310
 
311
+ from deepagents_cli.config import _load_dotenv
312
312
  from deepagents_cli.deploy.bundler import bundle, print_bundle_summary
313
313
  from deepagents_cli.deploy.config import (
314
314
  DEFAULT_CONFIG_FILENAME,
@@ -322,12 +322,17 @@ def _dev(
322
322
  discovered = find_config()
323
323
  cfg_path = discovered or Path.cwd() / DEFAULT_CONFIG_FILENAME
324
324
  project_root = cfg_path.parent
325
+ # Ensure the project .env is loaded before validation (see _deploy).
326
+ _load_dotenv(start_path=project_root)
325
327
 
326
328
  try:
327
329
  config = load_config(cfg_path)
328
330
  except FileNotFoundError:
329
331
  print(f"Error: Config file not found: {cfg_path}")
330
332
  raise SystemExit(1) from None
333
+ except ValueError as e:
334
+ print(f"Error: Invalid config: {e}")
335
+ raise SystemExit(1) from None
331
336
 
332
337
  errors = config.validate(project_root)
333
338
  if errors:
@@ -337,35 +342,43 @@ def _dev(
337
342
  raise SystemExit(1)
338
343
 
339
344
  build_dir = Path(tempfile.mkdtemp(prefix="deepagents-dev-"))
340
- bundle(config, project_root, build_dir)
341
- print_bundle_summary(config, build_dir)
342
-
343
- if shutil.which("langgraph") is None:
344
- print(
345
- "Error: `langgraph` CLI not found. Install it with:\n"
346
- " pip install 'langgraph-cli[inmem]'"
347
- )
348
- raise SystemExit(1)
345
+ try:
346
+ bundle(config, project_root, build_dir)
347
+ print_bundle_summary(config, build_dir)
349
348
 
350
- cmd = [
351
- "langgraph",
352
- "dev",
353
- "--no-browser",
354
- "--port",
355
- str(port),
356
- ]
357
- if allow_blocking:
358
- cmd.append("--allow-blocking")
349
+ if shutil.which("langgraph") is None:
350
+ print(
351
+ "Error: `langgraph` CLI not found. Install it with:\n"
352
+ " pip install 'langgraph-cli[inmem]'"
353
+ )
354
+ raise SystemExit(1)
359
355
 
360
- print(f"\nStarting langgraph dev on http://localhost:{port}")
361
- print(f"Build directory: {build_dir}")
362
- print(f"Running: {' '.join(cmd)}\n")
356
+ cmd = [
357
+ "langgraph",
358
+ "dev",
359
+ "--no-browser",
360
+ "--port",
361
+ str(port),
362
+ ]
363
+ if allow_blocking:
364
+ cmd.append("--allow-blocking")
365
+
366
+ print(f"\nStarting langgraph dev on http://localhost:{port}")
367
+ print(f"Build directory: {build_dir}")
368
+ print(f"Running: {' '.join(cmd)}\n")
369
+
370
+ # Pass through stdout/stderr so the user sees dev server logs live.
371
+ try:
372
+ result = subprocess.run(cmd, cwd=str(build_dir), check=False)
373
+ except KeyboardInterrupt:
374
+ print("\nShutting down.")
375
+ return
363
376
 
364
- # Pass through stdout/stderr so the user sees the dev server logs live.
365
- try:
366
- subprocess.run(cmd, cwd=str(build_dir), check=False)
367
- except KeyboardInterrupt:
368
- print("\nShutting down.")
377
+ if result.returncode != 0:
378
+ print(f"\nDev server exited with error (exit code {result.returncode}).")
379
+ raise SystemExit(result.returncode)
380
+ finally:
381
+ shutil.rmtree(build_dir, ignore_errors=True)
369
382
 
370
383
 
371
384
  def _run_langgraph_deploy(build_dir: Path, *, name: str) -> None:
@@ -11,9 +11,9 @@ The new minimal surface has exactly two sections:
11
11
  read it at runtime, but writes/edits to that path are blocked by a read-only
12
12
  middleware in the generated graph.
13
13
 
14
- Skills (`src/skills/`) and MCP servers (`src/mcp.json`) are auto-detected
15
- from the project layout. The agent's system prompt is read from
16
- `src/AGENTS.md` at bundle time — there is no `system_prompt` key.
14
+ Skills (`skills/`) and MCP servers (`mcp.json`) are auto-detected from the
15
+ project layout. The agent's system prompt is read from `AGENTS.md` at bundle
16
+ time — there is no `system_prompt` key.
17
17
  """
18
18
 
19
19
  from __future__ import annotations
@@ -23,12 +23,18 @@ import os
23
23
  import tomllib
24
24
  from dataclasses import dataclass, field
25
25
  from pathlib import Path
26
- from typing import Any
26
+ from typing import Any, Literal, get_args
27
27
 
28
- VALID_SANDBOX_PROVIDERS = frozenset(
29
- {"none", "daytona", "langsmith", "modal", "runloop"}
30
- )
31
- """Valid sandbox providers (mirrors sandbox_factory._PROVIDER_TO_WORKING_DIR)"""
28
+ SandboxProvider = Literal["none", "daytona", "langsmith", "modal", "runloop"]
29
+ """Valid sandbox provider identifiers."""
30
+
31
+ SandboxScope = Literal["thread", "assistant"]
32
+ """Valid sandbox scope values."""
33
+
34
+ VALID_SANDBOX_PROVIDERS: frozenset[str] = frozenset(get_args(SandboxProvider))
35
+ """Valid sandbox providers for deploy (subset of sandbox_factory, plus `"none"`)."""
36
+
37
+ VALID_SANDBOX_SCOPES: frozenset[str] = frozenset(get_args(SandboxScope))
32
38
 
33
39
  DEFAULT_CONFIG_FILENAME = "deepagents.toml"
34
40
 
@@ -40,13 +46,15 @@ MCP_FILENAME = "mcp.json"
40
46
 
41
47
  @dataclass(frozen=True)
42
48
  class AgentConfig:
43
- """``[agent]`` section — core agent identity."""
49
+ """`[agent]` section — core agent identity."""
44
50
 
45
51
  name: str
46
52
  model: str = "anthropic:claude-sonnet-4-6"
47
53
 
48
-
49
- VALID_SANDBOX_SCOPES = frozenset({"thread", "assistant"})
54
+ def __post_init__(self) -> None: # noqa: D105 — simple guard, not a public API
55
+ if not self.name.strip():
56
+ msg = "AgentConfig.name must be non-empty"
57
+ raise ValueError(msg)
50
58
 
51
59
 
52
60
  @dataclass(frozen=True)
@@ -65,10 +73,10 @@ class SandboxConfig:
65
73
  same assistant share a single sandbox and its filesystem.
66
74
  """
67
75
 
68
- provider: str = "none"
76
+ provider: SandboxProvider = "none"
69
77
  template: str = "deepagents-deploy"
70
78
  image: str = "python:3"
71
- scope: str = "thread"
79
+ scope: SandboxScope = "thread"
72
80
 
73
81
 
74
82
  @dataclass(frozen=True)
@@ -82,8 +90,7 @@ class DeployConfig:
82
90
  """Validate config against the filesystem.
83
91
 
84
92
  Args:
85
- project_root: Directory containing `deepagents.toml` (i.e.
86
- the `src/` dir in the canonical layout).
93
+ project_root: Directory containing `deepagents.toml`.
87
94
 
88
95
  Returns:
89
96
  List of validation error strings. Empty if valid.
@@ -168,13 +175,19 @@ def load_config(config_path: Path) -> DeployConfig:
168
175
  msg = f"Config file not found: {config_path}"
169
176
  raise FileNotFoundError(msg)
170
177
 
171
- with config_path.open("rb") as f:
172
- data = tomllib.load(f)
178
+ try:
179
+ with config_path.open("rb") as f:
180
+ data = tomllib.load(f)
181
+ except tomllib.TOMLDecodeError as exc:
182
+ msg = f"Syntax error in {config_path}: {exc}"
183
+ raise ValueError(msg) from exc
173
184
 
174
185
  return _parse_config(data)
175
186
 
176
187
 
177
188
  _ALLOWED_SECTIONS = frozenset({"agent", "sandbox"})
189
+ _ALLOWED_AGENT_KEYS = frozenset({"name", "model"})
190
+ _ALLOWED_SANDBOX_KEYS = frozenset({"provider", "template", "image", "scope"})
178
191
 
179
192
 
180
193
  def _parse_config(data: dict[str, Any]) -> DeployConfig:
@@ -195,18 +208,33 @@ def _parse_config(data: dict[str, Any]) -> DeployConfig:
195
208
  msg = "[agent].name is required in deepagents.toml"
196
209
  raise ValueError(msg)
197
210
 
198
- agent = AgentConfig(
199
- name=agent_data["name"],
200
- model=agent_data.get("model", "anthropic:claude-sonnet-4-6"),
201
- )
211
+ unknown_agent = set(agent_data.keys()) - _ALLOWED_AGENT_KEYS
212
+ if unknown_agent:
213
+ msg = (
214
+ f"Unknown key(s) in [agent]: {sorted(unknown_agent)}. "
215
+ f"Allowed: {sorted(_ALLOWED_AGENT_KEYS)}"
216
+ )
217
+ raise ValueError(msg)
218
+
219
+ # Only pass keys present in TOML; dataclass defaults handle the rest.
220
+ agent_kwargs: dict[str, Any] = {"name": agent_data["name"]}
221
+ if "model" in agent_data:
222
+ agent_kwargs["model"] = agent_data["model"]
223
+ agent = AgentConfig(**agent_kwargs)
202
224
 
203
225
  sandbox_data = data.get("sandbox", {})
204
- sandbox = SandboxConfig(
205
- provider=sandbox_data.get("provider", "none"),
206
- template=sandbox_data.get("template", "deepagents-deploy"),
207
- image=sandbox_data.get("image", "python:3"),
208
- scope=sandbox_data.get("scope", "thread"),
209
- )
226
+ unknown_sandbox = set(sandbox_data.keys()) - _ALLOWED_SANDBOX_KEYS
227
+ if unknown_sandbox:
228
+ msg = (
229
+ f"Unknown key(s) in [sandbox]: {sorted(unknown_sandbox)}. "
230
+ f"Allowed: {sorted(_ALLOWED_SANDBOX_KEYS)}"
231
+ )
232
+ raise ValueError(msg)
233
+
234
+ sandbox_kwargs: dict[str, Any] = {
235
+ k: sandbox_data[k] for k in _ALLOWED_SANDBOX_KEYS if k in sandbox_data
236
+ }
237
+ sandbox = SandboxConfig(**sandbox_kwargs)
210
238
 
211
239
  return DeployConfig(agent=agent, sandbox=sandbox)
212
240
 
@@ -261,7 +289,7 @@ def _validate_model_credentials(model: str) -> list[str]:
261
289
 
262
290
 
263
291
  def _validate_sandbox_credentials(provider: str) -> list[str]:
264
- """Check that the API key env var is set for the sandbox provider."""
292
+ """Check that at least one required API key env var is set for the provider."""
265
293
  required_vars = _SANDBOX_PROVIDER_ENV.get(provider)
266
294
  if required_vars is None:
267
295
  return []
@@ -276,9 +304,11 @@ def _validate_sandbox_credentials(provider: str) -> list[str]:
276
304
 
277
305
 
278
306
  def find_config(start_path: Path | None = None) -> Path | None:
279
- """Find `deepagents.toml` in the current directory.
307
+ """Find `deepagents.toml` in *start_path* (or cwd if not given).
308
+
309
+ Only checks the single directory — does not walk parent directories.
280
310
 
281
- Returns the path if found, or ``None`` otherwise.
311
+ Returns the path if found, or `None` otherwise.
282
312
  """
283
313
  current = (start_path or Path.cwd()).resolve()
284
314
  candidate = current / DEFAULT_CONFIG_FILENAME