deeploop 0.1.2__tar.gz → 0.1.4__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 (223) hide show
  1. {deeploop-0.1.2/src/deeploop.egg-info → deeploop-0.1.4}/PKG-INFO +29 -13
  2. {deeploop-0.1.2 → deeploop-0.1.4}/README.md +28 -12
  3. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/provider-selection-registry.yaml +4 -1
  4. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/provider-setup-registry.yaml +2 -2
  5. {deeploop-0.1.2 → deeploop-0.1.4}/pyproject.toml +1 -1
  6. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/invoke_provider_prompt.py +27 -4
  7. deeploop-0.1.4/src/deeploop/__init__.py +1 -0
  8. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/artifacts/artifact_packager.py +37 -1
  9. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/cli/init_mission.py +23 -1
  10. deeploop-0.1.4/src/deeploop/cli/run_project.py +165 -0
  11. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_operator_surface.py +8 -8
  12. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_discovery.py +160 -16
  13. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_management.py +28 -15
  14. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_runtime.py +3 -5
  15. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/orchestrator.py +2 -96
  16. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/project_bootstrap.py +301 -1
  17. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/project_runner.py +57 -0
  18. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/project_contract.py +4 -0
  19. deeploop-0.1.4/src/deeploop/runtime/openai_compatible_adapter.py +167 -0
  20. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/provider_launcher.py +312 -51
  21. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/recursive_agent_runtime.py +212 -21
  22. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/testing/test_tiers.py +4 -0
  23. {deeploop-0.1.2 → deeploop-0.1.4/src/deeploop.egg-info}/PKG-INFO +29 -13
  24. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop.egg-info/SOURCES.txt +2 -0
  25. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_artifact_packager.py +104 -0
  26. deeploop-0.1.4/tests/test_end_to_end_smoke.py +386 -0
  27. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_discovery.py +62 -0
  28. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_management.py +10 -10
  29. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_monitor.py +10 -10
  30. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_runtime.py +22 -3
  31. deeploop-0.1.4/tests/test_openai_compatible_adapter.py +70 -0
  32. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_package_structure.py +45 -0
  33. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_project_contract.py +69 -0
  34. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_project_runner.py +186 -0
  35. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_provider_launcher.py +162 -0
  36. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_public_bootstrap.py +2 -0
  37. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_recursive_agent_runtime.py +281 -2
  38. deeploop-0.1.4/tests/test_release_docker_validation.py +132 -0
  39. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_repo_contract.py +3 -2
  40. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_test_tiers.py +12 -0
  41. deeploop-0.1.2/src/deeploop/__init__.py +0 -1
  42. deeploop-0.1.2/src/deeploop/cli/run_project.py +0 -59
  43. deeploop-0.1.2/tests/test_end_to_end_smoke.py +0 -135
  44. deeploop-0.1.2/tests/test_release_docker_validation.py +0 -70
  45. {deeploop-0.1.2 → deeploop-0.1.4}/LICENSE +0 -0
  46. {deeploop-0.1.2 → deeploop-0.1.4}/MANIFEST.in +0 -0
  47. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/confound-guard.yaml +0 -0
  48. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/evidence-policy.yaml +0 -0
  49. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/fresh-context-redteam.yaml +0 -0
  50. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/gates.yaml +0 -0
  51. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/mission-outer-loop.yaml +0 -0
  52. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/novelty-refresh.yaml +0 -0
  53. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/operator-boundaries.yaml +0 -0
  54. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/research-sanity-gates.yaml +0 -0
  55. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/self-correction.yaml +0 -0
  56. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/self-optimization.yaml +0 -0
  57. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/state-machine.yaml +0 -0
  58. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/statistical-rigor.yaml +0 -0
  59. {deeploop-0.1.2 → deeploop-0.1.4}/configs/autonomy/utility-scorer.yaml +0 -0
  60. {deeploop-0.1.2 → deeploop-0.1.4}/configs/evaluation/statistical-rigor.yaml +0 -0
  61. {deeploop-0.1.2 → deeploop-0.1.4}/configs/evaluation/system-metrics.yaml +0 -0
  62. {deeploop-0.1.2 → deeploop-0.1.4}/configs/execution-profiles/inference-families.yaml +0 -0
  63. {deeploop-0.1.2 → deeploop-0.1.4}/configs/execution-profiles/training-presets.yaml +0 -0
  64. {deeploop-0.1.2 → deeploop-0.1.4}/configs/ledger/policy.yaml +0 -0
  65. {deeploop-0.1.2 → deeploop-0.1.4}/configs/manifests/run-manifest-template.json +0 -0
  66. {deeploop-0.1.2 → deeploop-0.1.4}/configs/memory/registry.yaml +0 -0
  67. {deeploop-0.1.2 → deeploop-0.1.4}/configs/operating-model/modes.yaml +0 -0
  68. {deeploop-0.1.2 → deeploop-0.1.4}/configs/platform/expansion.yaml +0 -0
  69. {deeploop-0.1.2 → deeploop-0.1.4}/configs/policy/placement.yaml +0 -0
  70. {deeploop-0.1.2 → deeploop-0.1.4}/configs/resource-tiers/tiers.yaml +0 -0
  71. {deeploop-0.1.2 → deeploop-0.1.4}/configs/roles/agent-roles.yaml +0 -0
  72. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/artifact-package-contract.yaml +0 -0
  73. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/backend-policy.yaml +0 -0
  74. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/mission-package.yaml +0 -0
  75. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/mission-scheduler.yaml +0 -0
  76. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/recovery-policy.yaml +0 -0
  77. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/recursive-agent-runtime-provider.example.yaml +0 -0
  78. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/recursive-agent-runtime.yaml +0 -0
  79. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/release-candidate-policy.yaml +0 -0
  80. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/self-healing-runtime.yaml +0 -0
  81. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/stage-kernel-registry.yaml +0 -0
  82. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/substrate-boundary.yaml +0 -0
  83. {deeploop-0.1.2 → deeploop-0.1.4}/configs/runtime/translation-long-run-baseline-queue.yaml +0 -0
  84. {deeploop-0.1.2 → deeploop-0.1.4}/configs/sandbox/agent-launch-policy.yaml +0 -0
  85. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/agent-handoff.schema.json +0 -0
  86. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/confound-guard-report.schema.json +0 -0
  87. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/ledger-entry.schema.json +0 -0
  88. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-acceptance-criteria.schema.json +0 -0
  89. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-action.schema.json +0 -0
  90. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-artifact-package.schema.json +0 -0
  91. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-branch-record.schema.json +0 -0
  92. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-decision.schema.json +0 -0
  93. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-meta-eval.schema.json +0 -0
  94. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-operator-request.schema.json +0 -0
  95. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/mission-state.schema.json +0 -0
  96. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/recursive-agent-result.schema.json +0 -0
  97. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/release-candidate-review.schema.json +0 -0
  98. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/research-memory-entry.schema.json +0 -0
  99. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/research-sanity-report.schema.json +0 -0
  100. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/run-manifest.schema.json +0 -0
  101. {deeploop-0.1.2 → deeploop-0.1.4}/schemas/self-correction-report.schema.json +0 -0
  102. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/init_mission.py +0 -0
  103. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/manage_mission.py +0 -0
  104. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/monitor_mission.py +0 -0
  105. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/package_mission.py +0 -0
  106. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/record_finding.py +0 -0
  107. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_confound_guard.py +0 -0
  108. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_fresh_context_redteam.py +0 -0
  109. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_mission.py +0 -0
  110. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_mission_scheduler.py +0 -0
  111. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_novelty_refresh.py +0 -0
  112. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_project.py +0 -0
  113. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_recursive_agent_loop.py +0 -0
  114. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_self_correction.py +0 -0
  115. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_self_optimization.py +0 -0
  116. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_statistical_rigor.py +0 -0
  117. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/mission/run_utility_scorer.py +0 -0
  118. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_confound_guard.py +0 -0
  119. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_queue.py +0 -0
  120. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_recoverable_stage.py +0 -0
  121. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_sanity_gate.py +0 -0
  122. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_stage_kernel.py +0 -0
  123. {deeploop-0.1.2 → deeploop-0.1.4}/scripts/runtime/run_statistical_rigor.py +0 -0
  124. {deeploop-0.1.2 → deeploop-0.1.4}/setup.cfg +0 -0
  125. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/_build.py +0 -0
  126. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/artifacts/__init__.py +0 -0
  127. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/artifacts/mission_package.py +0 -0
  128. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/artifacts/release_automation.py +0 -0
  129. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/artifacts/submission_export.py +0 -0
  130. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/__init__.py +0 -0
  131. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/gate_taxonomy.py +0 -0
  132. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/mission_autonomy.py +0 -0
  133. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/mission_contract_snapshot.py +0 -0
  134. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/operating_modes.py +0 -0
  135. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/autonomy/operator_inbox.py +0 -0
  136. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/cli/__init__.py +0 -0
  137. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/cli/analyze.py +0 -0
  138. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/cli/export_mission.py +0 -0
  139. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/cli/package_mission.py +0 -0
  140. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/__init__.py +0 -0
  141. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/config_paths.py +0 -0
  142. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/dotted.py +0 -0
  143. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/ledger.py +0 -0
  144. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/paths.py +0 -0
  145. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/phase_defaults.py +0 -0
  146. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/core/structured_io.py +0 -0
  147. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/fresh_context_redteam.py +0 -0
  148. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/__init__.py +0 -0
  149. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_autonomy_gap_telemetry.py +0 -0
  150. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_constants.py +0 -0
  151. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_monitor_classification.py +0 -0
  152. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_monitor_render.py +0 -0
  153. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_monitor_snapshot.py +0 -0
  154. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_runtime_contract.py +0 -0
  155. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/_runtime_persistence.py +0 -0
  156. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_acceptance.py +0 -0
  157. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_decision_engine.py +0 -0
  158. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_memory.py +0 -0
  159. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_monitor.py +0 -0
  160. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_progress.py +0 -0
  161. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_scheduler.py +0 -0
  162. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/mission_state.py +0 -0
  163. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/mission/plain_folder_followup.py +0 -0
  164. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/platform/__init__.py +0 -0
  165. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/platform/contracts.py +0 -0
  166. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/__init__.py +0 -0
  167. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/confound_guard.py +0 -0
  168. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/indexed_memory.py +0 -0
  169. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/novelty_refresh.py +0 -0
  170. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/sanity_gates.py +0 -0
  171. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/self_correction.py +0 -0
  172. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/self_optimization.py +0 -0
  173. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/statistical_rigor.py +0 -0
  174. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/research/utility_scorer.py +0 -0
  175. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/__init__.py +0 -0
  176. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/_prompt_renderer.py +0 -0
  177. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/_stage_kernel_registry.py +0 -0
  178. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/_stage_kernel_reporting.py +0 -0
  179. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/_stage_kernel_resolution.py +0 -0
  180. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/adaptation_training_runtime.py +0 -0
  181. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/copilot_adapter.py +0 -0
  182. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/metric_ratchets.py +0 -0
  183. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/mission_executor_registry.py +0 -0
  184. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/plain_folder_adapter.py +0 -0
  185. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/runtime_recovery.py +0 -0
  186. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/sandbox.py +0 -0
  187. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/self_healing_runtime.py +0 -0
  188. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/runtime/stage_kernels.py +0 -0
  189. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/testing/__init__.py +0 -0
  190. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/testing/acceptance_campaigns.py +0 -0
  191. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/testing/plain_folder_proof_matrix.py +0 -0
  192. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop/testing/proof_matrix_reviews.py +0 -0
  193. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop.egg-info/dependency_links.txt +0 -0
  194. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop.egg-info/entry_points.txt +0 -0
  195. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop.egg-info/requires.txt +0 -0
  196. {deeploop-0.1.2 → deeploop-0.1.4}/src/deeploop.egg-info/top_level.txt +0 -0
  197. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_acceptance_campaigns.py +0 -0
  198. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_adaptation_training_runtime.py +0 -0
  199. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_confound_guard.py +0 -0
  200. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_core_paths.py +0 -0
  201. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_fresh_context_redteam.py +0 -0
  202. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_indexed_research_memory.py +0 -0
  203. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_metric_ratchets.py +0 -0
  204. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_autonomy.py +0 -0
  205. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_decision_engine.py +0 -0
  206. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_executor_registry.py +0 -0
  207. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_package.py +0 -0
  208. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_scheduler.py +0 -0
  209. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_mission_state.py +0 -0
  210. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_novelty_refresh.py +0 -0
  211. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_plain_folder_proof_matrix.py +0 -0
  212. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_platform_integration.py +0 -0
  213. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_proof_matrix_reviews.py +0 -0
  214. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_record_finding.py +0 -0
  215. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_release_automation.py +0 -0
  216. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_runtime_recovery.py +0 -0
  217. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_sandbox.py +0 -0
  218. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_self_correction.py +0 -0
  219. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_self_healing_runtime.py +0 -0
  220. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_self_optimization.py +0 -0
  221. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_stage_kernels.py +0 -0
  222. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_statistical_rigor.py +0 -0
  223. {deeploop-0.1.2 → deeploop-0.1.4}/tests/test_utility_scorer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deeploop
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: DeepLoop autonomous research autopilot control plane.
5
5
  Author: DeepLoop maintainers
6
6
  License-Expression: MIT
@@ -93,26 +93,35 @@ DeepLoop **owns behavior** and orchestration; substrate repos own reusable domai
93
93
  cp -R examples/translation-budget-ladder PROJECT_FOLDER
94
94
  ```
95
95
 
96
- - fastest path:
96
+ - fastest path:
97
97
 
98
98
  ```text
99
99
  deeploop run --project-root examples/translation-budget-ladder --until-complete
100
100
  ```
101
101
 
102
- > **Note:** If `<project-folder>/.deeploop/missions/*.yaml` files exist, `deeploop run`
103
- > automatically uses the first one instead of bootstrapping a blank mission.
104
- > For a plain folder with no existing config, it bootstraps from the folder's facts.
105
- > To target a specific explicit config directly, use
106
- > `deeploop init --config <mission-config.yaml>` followed by
107
- > `deeploop start --mission-state <mission-state.json>`.
102
+ > **Note:** If `<project-folder>/.deeploop/missions/*.yaml` files exist, `deeploop run`
103
+ > automatically uses the first one instead of bootstrapping a blank mission.
104
+ > For a plain folder with no existing config, it bootstraps from the folder's facts.
105
+ > If the folder is rough but still recognizable, DeepLoop can initialize with
106
+ > disclosed clarifications/defaults and keep the project folder unchanged. To
107
+ > target a specific explicit config directly, use `deeploop init --config
108
+ > <mission-config.yaml>` followed by `deeploop start --mission-state
109
+ > <mission-state.json>`.
108
110
 
109
- - explicit operator path:
111
+ - discovery / operator path:
110
112
 
111
- ```text
112
- deeploop init --project-root examples/translation-budget-ladder --force
113
- ```
113
+ ```text
114
+ deeploop init --project-root PROJECT_FOLDER --force
115
+ deeploop init --discover --project-root PROJECT_FOLDER --force
116
+ ```
117
+
118
+ Use plain `deeploop init --project-root ...` when the folder is rough but
119
+ already recognizable. Add `--discover` when you want DeepLoop to ask
120
+ clarifying questions before kickoff.
114
121
 
115
- On a copied folder, substitute `PROJECT_FOLDER` in the commands above.
122
+ On a copied folder, substitute `PROJECT_FOLDER` in the commands above. If
123
+ DeepLoop cannot safely bootstrap the folder yet, it stops with bounded
124
+ bootstrap-repair guidance instead of mutating the project.
116
125
 
117
126
  5. **Use the operator CLI when a run pauses**
118
127
 
@@ -124,6 +133,13 @@ DeepLoop **owns behavior** and orchestration; substrate repos own reusable domai
124
133
 
125
134
  The `deeploop` CLI is the single entry point — `run`, `init`, `status`, `inbox`, `resume`, and more are all subcommands.
126
135
 
136
+ ## Readiness at a glance
137
+
138
+ - **Fastest supported path:** Linux, Python 3.11+, `pip install deeploop`, `make setup`, `make public-bootstrap-check`, then `deeploop run --project-root <project-folder> --until-complete`
139
+ - **Messy starts are supported:** rough plain-folder projects can initialize with disclosed clarifications/defaults, or you can use `deeploop init --discover ...` for a guided kickoff
140
+ - **Repair stays bounded:** if the folder is missing the plain-folder bootstrap contract, DeepLoop exits with bootstrap-repair guidance and suggested starter inputs instead of silently rewriting project files
141
+ - **Current release gate:** `make public-bootstrap-check`, `make docker-release-validate`, and `make docs-build`, with PyPI publish only from a published GitHub Release whose tag matches `project.version`
142
+
127
143
  ## Best fit today
128
144
 
129
145
  DeepLoop is best when you already have:
@@ -54,26 +54,35 @@ DeepLoop **owns behavior** and orchestration; substrate repos own reusable domai
54
54
  cp -R examples/translation-budget-ladder PROJECT_FOLDER
55
55
  ```
56
56
 
57
- - fastest path:
57
+ - fastest path:
58
58
 
59
59
  ```text
60
60
  deeploop run --project-root examples/translation-budget-ladder --until-complete
61
61
  ```
62
62
 
63
- > **Note:** If `<project-folder>/.deeploop/missions/*.yaml` files exist, `deeploop run`
64
- > automatically uses the first one instead of bootstrapping a blank mission.
65
- > For a plain folder with no existing config, it bootstraps from the folder's facts.
66
- > To target a specific explicit config directly, use
67
- > `deeploop init --config <mission-config.yaml>` followed by
68
- > `deeploop start --mission-state <mission-state.json>`.
63
+ > **Note:** If `<project-folder>/.deeploop/missions/*.yaml` files exist, `deeploop run`
64
+ > automatically uses the first one instead of bootstrapping a blank mission.
65
+ > For a plain folder with no existing config, it bootstraps from the folder's facts.
66
+ > If the folder is rough but still recognizable, DeepLoop can initialize with
67
+ > disclosed clarifications/defaults and keep the project folder unchanged. To
68
+ > target a specific explicit config directly, use `deeploop init --config
69
+ > <mission-config.yaml>` followed by `deeploop start --mission-state
70
+ > <mission-state.json>`.
69
71
 
70
- - explicit operator path:
72
+ - discovery / operator path:
71
73
 
72
- ```text
73
- deeploop init --project-root examples/translation-budget-ladder --force
74
- ```
74
+ ```text
75
+ deeploop init --project-root PROJECT_FOLDER --force
76
+ deeploop init --discover --project-root PROJECT_FOLDER --force
77
+ ```
78
+
79
+ Use plain `deeploop init --project-root ...` when the folder is rough but
80
+ already recognizable. Add `--discover` when you want DeepLoop to ask
81
+ clarifying questions before kickoff.
75
82
 
76
- On a copied folder, substitute `PROJECT_FOLDER` in the commands above.
83
+ On a copied folder, substitute `PROJECT_FOLDER` in the commands above. If
84
+ DeepLoop cannot safely bootstrap the folder yet, it stops with bounded
85
+ bootstrap-repair guidance instead of mutating the project.
77
86
 
78
87
  5. **Use the operator CLI when a run pauses**
79
88
 
@@ -85,6 +94,13 @@ DeepLoop **owns behavior** and orchestration; substrate repos own reusable domai
85
94
 
86
95
  The `deeploop` CLI is the single entry point — `run`, `init`, `status`, `inbox`, `resume`, and more are all subcommands.
87
96
 
97
+ ## Readiness at a glance
98
+
99
+ - **Fastest supported path:** Linux, Python 3.11+, `pip install deeploop`, `make setup`, `make public-bootstrap-check`, then `deeploop run --project-root <project-folder> --until-complete`
100
+ - **Messy starts are supported:** rough plain-folder projects can initialize with disclosed clarifications/defaults, or you can use `deeploop init --discover ...` for a guided kickoff
101
+ - **Repair stays bounded:** if the folder is missing the plain-folder bootstrap contract, DeepLoop exits with bootstrap-repair guidance and suggested starter inputs instead of silently rewriting project files
102
+ - **Current release gate:** `make public-bootstrap-check`, `make docker-release-validate`, and `make docs-build`, with PyPI publish only from a published GitHub Release whose tag matches `project.version`
103
+
88
104
  ## Best fit today
89
105
 
90
106
  DeepLoop is best when you already have:
@@ -112,7 +112,7 @@ selection_profiles:
112
112
  - vllm
113
113
  - local-transformers
114
114
  openai-compatible-api-control-plane:
115
- status: reserved-runtime-adapter
115
+ status: implemented
116
116
  provider_family: openai-compatible-api
117
117
  backend: openai-compatible-api
118
118
  model_selection:
@@ -125,6 +125,9 @@ selection_profiles:
125
125
  provider_family_switch: explicit-only
126
126
  backend_switch: provider-native
127
127
  model_fallback: explicit-model-ladder-only
128
+ notes:
129
+ - runtime support currently covers prompt/result control-plane flows that return structured JSON
130
+ - recursive-agent tool execution remains on the copilot-cli path
128
131
  anthropic-api-control-plane:
129
132
  status: reserved-runtime-adapter
130
133
  provider_family: anthropic-api
@@ -50,7 +50,7 @@ provider_families:
50
50
  openai-compatible-api:
51
51
  display_name: OpenAI-compatible API providers
52
52
  public_contract_tier: first-class
53
- runtime_integration: deferred
53
+ runtime_integration: implemented
54
54
  required_tools:
55
55
  - command: python
56
56
  purpose: control-plane entrypoint
@@ -71,7 +71,7 @@ provider_families:
71
71
  expectation: set in the operator shell or runner environment
72
72
  manual:
73
73
  - if OPENAI_BASE_URL is set, confirm the endpoint is reachable over HTTPS
74
- - DeepLoop does not yet ship a public request adapter or mission/runtime selector for this family
74
+ - the public adapter currently covers prompt/result control-plane flows; it does not add Copilot-style tool execution
75
75
  anthropic-api:
76
76
  display_name: Anthropic API providers
77
77
  public_contract_tier: first-class
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deeploop"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  description = "DeepLoop autonomous research autopilot control plane."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,13 +1,36 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
+ import os
4
5
  import sys
5
6
  from pathlib import Path
6
7
 
7
- REPO_ROOT = Path(__file__).resolve().parents[2]
8
- SRC_ROOT = REPO_ROOT / "src"
9
- if str(SRC_ROOT) not in sys.path:
10
- sys.path.insert(0, str(SRC_ROOT))
8
+ SCRIPT_PATH = Path(__file__).resolve()
9
+ REPO_ROOT = SCRIPT_PATH.parents[2]
10
+
11
+
12
+ def _bootstrap_import_path() -> None:
13
+ candidates: list[Path] = []
14
+
15
+ cache_src = os.environ.get("DEEPLOOP_RUNTIME_CACHE_SRC", "").strip()
16
+ if cache_src:
17
+ candidates.append(Path(cache_src).expanduser().resolve())
18
+
19
+ repo_src = REPO_ROOT / "src"
20
+ if repo_src.is_dir():
21
+ candidates.append(repo_src)
22
+
23
+ package_root = SCRIPT_PATH.parents[3]
24
+ if package_root.name == "deeploop" and (package_root / "__init__.py").is_file():
25
+ candidates.append(package_root.parent)
26
+
27
+ for candidate in candidates:
28
+ candidate_text = str(candidate)
29
+ if candidate.is_dir() and candidate_text not in sys.path:
30
+ sys.path.insert(0, candidate_text)
31
+
32
+
33
+ _bootstrap_import_path()
11
34
 
12
35
  from deeploop.runtime.provider_launcher import run_provider_prompt
13
36
 
@@ -0,0 +1 @@
1
+ __version__ = "0.1.4"
@@ -850,6 +850,39 @@ def _artifact_bullets(artifacts: list[dict[str, Any]], artifact_ids: list[str],
850
850
  return bullets
851
851
 
852
852
 
853
+ def _mission_runtime_handoff_bullets(mission_state: dict[str, Any], *, ledger_entries: int) -> list[str]:
854
+ mission_runtime = mission_state.get("mission_runtime") if isinstance(mission_state.get("mission_runtime"), dict) else {}
855
+ if not mission_runtime:
856
+ return [f"Ledger entries captured: {ledger_entries}."]
857
+ bullets = [
858
+ "Mission runtime: "
859
+ f"{mission_runtime.get('status', 'unknown')} after "
860
+ f"{int(mission_runtime.get('iterations_completed', 0) or 0)} bounded iteration(s)."
861
+ ]
862
+ telemetry = (
863
+ mission_runtime.get("autonomy_gap_telemetry")
864
+ if isinstance(mission_runtime.get("autonomy_gap_telemetry"), dict)
865
+ else {}
866
+ )
867
+ counts = telemetry.get("counts") if isinstance(telemetry.get("counts"), dict) else {}
868
+ if counts:
869
+ bullets.append(
870
+ "Recovery telemetry: "
871
+ f"soft_gates={int(counts.get('soft_gates_total', 0) or 0)}, "
872
+ f"bounded_recoveries={int(counts.get('bounded_recovery_outcomes', 0) or 0)}, "
873
+ f"operator_requests={int(counts.get('operator_requests_total', 0) or 0)}."
874
+ )
875
+ auto_recovered = int(counts.get("temporary_gap_auto_recovered", 0) or 0)
876
+ escalated = int(counts.get("temporary_gap_escalated", 0) or 0)
877
+ if auto_recovered or escalated:
878
+ bullets.append(
879
+ "Temporary gaps: "
880
+ f"auto_recovered={auto_recovered}, escalated={escalated}."
881
+ )
882
+ bullets.append(f"Ledger entries captured: {ledger_entries}.")
883
+ return bullets
884
+
885
+
853
886
  def _data_artifact_reference_only(metadata: dict[str, Any]) -> bool:
854
887
  return metadata.get("package") is False or str(
855
888
  metadata.get("packaging_policy") or metadata.get("package_policy") or ""
@@ -1155,9 +1188,11 @@ def package_mission_artifacts(
1155
1188
  register_artifact(report_path, category=category, metadata=metadata)
1156
1189
 
1157
1190
  ledger_path = mission_root / "ledger.jsonl"
1191
+ ledger_entries: list[dict[str, Any]] = []
1158
1192
  if ledger_path.exists():
1159
1193
  ledger_artifact_id = register_artifact(ledger_path, category="ledgers")
1160
- for entry in _load_jsonl(ledger_path):
1194
+ ledger_entries = _load_jsonl(ledger_path)
1195
+ for entry in ledger_entries:
1161
1196
  related_paths = entry.get("related_paths", [])
1162
1197
  for raw_path in related_paths:
1163
1198
  if not isinstance(raw_path, str):
@@ -1382,6 +1417,7 @@ def package_mission_artifacts(
1382
1417
  f"Current phase: {mission_state.get('current_phase')} ({mission_state.get('status')})",
1383
1418
  f"Packaged {len(artifacts)} artifacts across {len(run_bundles)} manifest bundles.",
1384
1419
  ]
1420
+ operator_bullets.extend(_mission_runtime_handoff_bullets(mission_state, ledger_entries=len(ledger_entries)))
1385
1421
  if missing_required_artifacts_summary:
1386
1422
  operator_bullets.append(missing_required_artifacts_summary)
1387
1423
  next_actions = mission_state.get("next_actions", {})
@@ -8,7 +8,11 @@ from deeploop.core.paths import SCRATCH_DIR, WORKSPACE_ROOT, WORKSPACE_ROOT_ENV_
8
8
  from deeploop.core.structured_io import write_text, write_yaml_mapping
9
9
  from deeploop.mission.mission_discovery import run_interactive_discovery
10
10
  from deeploop.mission.orchestrator import initialize_mission
11
- from deeploop.mission.project_bootstrap import build_mission_config_from_project_root
11
+ from deeploop.mission.project_bootstrap import (
12
+ build_mission_config_from_project_root,
13
+ render_bootstrap_repair_lines,
14
+ render_mission_contract_summary_lines,
15
+ )
12
16
 
13
17
 
14
18
  def _add_init_args(parser: argparse.ArgumentParser) -> None:
@@ -31,6 +35,14 @@ def _add_init_args(parser: argparse.ArgumentParser) -> None:
31
35
  parser.add_argument("--force", action="store_true", help="Replace any existing mission root with the same mission id.")
32
36
 
33
37
 
38
+ def _print_readiness_summary(config: dict[str, object]) -> None:
39
+ mission_contract = config.get("mission_contract") if isinstance(config.get("mission_contract"), dict) else {}
40
+ if not mission_contract:
41
+ return
42
+ for line in render_mission_contract_summary_lines(mission_contract, format="plain"):
43
+ print(f"mission-init: {line}" if line else "mission-init:")
44
+
45
+
34
46
  def _init_mission(args: argparse.Namespace) -> int:
35
47
  has_config = bool(getattr(args, "config", None))
36
48
  has_project_root = bool(getattr(args, "project_root", None))
@@ -75,9 +87,18 @@ def _init_mission(args: argparse.Namespace) -> int:
75
87
  write_text(persisted_config_path, Path(discovery["config_path"]).read_text(encoding="utf-8"))
76
88
  print(f"mission-init: used confirmed discovery config {discovery['config_path']}")
77
89
  print(f"mission-init: wrote generated config to {persisted_config_path}")
90
+ _print_readiness_summary(discovery["config"])
78
91
  elif has_project_root:
79
92
  project_root = Path(args.project_root).expanduser().resolve()
80
93
  generated_config = build_mission_config_from_project_root(project_root, mission_id=getattr(args, "mission_id", None))
94
+ bootstrap_repair = (
95
+ generated_config.get("bootstrap_repair") if isinstance(generated_config.get("bootstrap_repair"), dict) else None
96
+ )
97
+ if isinstance(bootstrap_repair, dict) and str(bootstrap_repair.get("status") or "").strip().lower() == "required":
98
+ print(f"mission-init: project-root bootstrap needs repair for {project_root}", file=sys.stderr)
99
+ for line in render_bootstrap_repair_lines(bootstrap_repair, format="plain"):
100
+ print(f"mission-init: {line}" if line else "mission-init:", file=sys.stderr)
101
+ return 2
81
102
  generated_config_dir = SCRATCH_DIR / "mission_bootstrap_configs"
82
103
  generated_config_dir.mkdir(parents=True, exist_ok=True)
83
104
  generated_config_path = generated_config_dir / f"{generated_config['mission']['id']}.yaml"
@@ -87,6 +108,7 @@ def _init_mission(args: argparse.Namespace) -> int:
87
108
  write_text(persisted_config_path, generated_config_path.read_text(encoding="utf-8"))
88
109
  print(f"mission-init: bootstrapped mission config from project folder {project_root}")
89
110
  print(f"mission-init: wrote generated config to {persisted_config_path}")
111
+ _print_readiness_summary(generated_config)
90
112
  else:
91
113
  result = initialize_mission(Path(args.config).expanduser().resolve(), force=getattr(args, "force", False))
92
114
 
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from deeploop.mission.project_bootstrap import render_bootstrap_repair_lines
10
+ from deeploop.mission.project_runner import _jsonify, run_project_until_complete
11
+
12
+
13
+ def _add_run_args(parser: argparse.ArgumentParser) -> None:
14
+ parser.add_argument(
15
+ "--project-root",
16
+ required=True,
17
+ help="Path to the plain researcher project folder. `deeploop run` bootstraps or reuses the mission state for you.",
18
+ )
19
+ parser.add_argument("--mission-id", help="Optional override for the generated mission id.")
20
+ parser.add_argument("--force", action="store_true", help="Replace any existing mission root with the same mission id.")
21
+ parser.add_argument(
22
+ "--until-complete",
23
+ action="store_true",
24
+ required=True,
25
+ help=(
26
+ "Keep extending bounded runtime passes until the mission completes or hits a true operator handoff. "
27
+ "Use `deeploop init` plus `deeploop start`/`deeploop resume` instead when you want manual control."
28
+ ),
29
+ )
30
+ parser.add_argument(
31
+ "--chunk-iterations",
32
+ type=int,
33
+ default=8,
34
+ help="How many additional bounded mission-runtime iterations to grant per pass.",
35
+ )
36
+ parser.add_argument(
37
+ "--max-total-iterations",
38
+ type=int,
39
+ default=256,
40
+ help="Absolute mission-runtime iteration budget across the full `--until-complete` run.",
41
+ )
42
+
43
+
44
+ def _first_next_command(snapshot: dict[str, Any] | None) -> str | None:
45
+ if not isinstance(snapshot, dict):
46
+ return None
47
+ operator_console = snapshot.get("operator_console")
48
+ if not isinstance(operator_console, dict):
49
+ return None
50
+ next_commands = operator_console.get("next_commands")
51
+ if not isinstance(next_commands, list):
52
+ return None
53
+ for entry in next_commands:
54
+ if isinstance(entry, dict):
55
+ command = str(entry.get("command") or "").strip()
56
+ if command:
57
+ return command
58
+ return None
59
+
60
+
61
+ def _resume_summary_line(result: dict[str, Any]) -> str | None:
62
+ resume_summary = result.get("resume_summary")
63
+ if not isinstance(resume_summary, dict):
64
+ return None
65
+ parts: list[str] = []
66
+ if resume_summary.get("resumed_existing_mission"):
67
+ initial_iterations = int(resume_summary.get("initial_iterations_completed", 0) or 0)
68
+ initial_status = str(resume_summary.get("initial_runtime_status") or "unknown")
69
+ parts.append(f"reused prior mission state ({initial_iterations} recorded iteration(s), status `{initial_status}`)")
70
+ bounded_resume_passes = int(resume_summary.get("bounded_resume_passes", 0) or 0)
71
+ if bounded_resume_passes > 0:
72
+ parts.append(f"auto-resumed {bounded_resume_passes} bounded pass(es)")
73
+ soft_recovery_resume_passes = int(resume_summary.get("soft_recovery_resume_passes", 0) or 0)
74
+ if soft_recovery_resume_passes > 0:
75
+ parts.append(f"{soft_recovery_resume_passes} via soft-gate recovery")
76
+ if not parts:
77
+ return None
78
+ return "; ".join(parts)
79
+
80
+
81
+ def _noncompleted_summary_lines(result: dict[str, Any]) -> list[str]:
82
+ status = str(result.get("status") or "stopped")
83
+ bootstrap_repair = result.get("bootstrap_repair") if isinstance(result.get("bootstrap_repair"), dict) else None
84
+ if status == "bootstrap-repair-required" and isinstance(bootstrap_repair, dict):
85
+ return [
86
+ "DeepLoop could not bootstrap this project root yet.",
87
+ f"- outcome: `{status}`",
88
+ *render_bootstrap_repair_lines(bootstrap_repair, format="plain"),
89
+ ]
90
+ snapshot = result.get("snapshot") if isinstance(result.get("snapshot"), dict) else None
91
+ operator_console = snapshot.get("operator_console") if isinstance(snapshot, dict) else None
92
+ headline = (
93
+ str(operator_console.get("headline") or "").strip()
94
+ if isinstance(operator_console, dict)
95
+ else ""
96
+ )
97
+ summary = (
98
+ str(operator_console.get("summary") or "").strip()
99
+ if isinstance(operator_console, dict)
100
+ else ""
101
+ )
102
+ recommendation = (
103
+ str(operator_console.get("recommendation") or "").strip()
104
+ if isinstance(operator_console, dict)
105
+ else ""
106
+ )
107
+ mission_state_path = result.get("mission_state_path")
108
+ next_command = _first_next_command(snapshot)
109
+ lines = [
110
+ "DeepLoop did not complete this run.",
111
+ f"- outcome: `{status}`",
112
+ ]
113
+ if headline:
114
+ lines.append(f"- handoff: {headline}")
115
+ if summary:
116
+ lines.append(f"- summary: {summary}")
117
+ elif status == "max-total-iterations":
118
+ lines.append("- summary: Reached the total `--max-total-iterations` budget before completion.")
119
+ if recommendation:
120
+ lines.append(f"- recommendation: {recommendation}")
121
+ resume_line = _resume_summary_line(result)
122
+ if resume_line:
123
+ lines.append(f"- resume: {resume_line}")
124
+ if next_command:
125
+ lines.append(f"- next_command: `{next_command}`")
126
+ elif mission_state_path:
127
+ lines.append(f"- next_command: `deeploop status --mission-state {mission_state_path}`")
128
+ return lines
129
+
130
+
131
+ def _run_project(args: argparse.Namespace) -> int:
132
+ if not args.until_complete:
133
+ print(
134
+ "error: `deeploop run` requires `--until-complete`; use `deeploop init` plus "
135
+ "`deeploop start`/`deeploop resume` for manual step-by-step control.",
136
+ flush=True,
137
+ )
138
+ return 2
139
+ result = run_project_until_complete(
140
+ Path(args.project_root),
141
+ mission_id=getattr(args, "mission_id", None),
142
+ force=getattr(args, "force", False),
143
+ chunk_iterations=getattr(args, "chunk_iterations", 8),
144
+ max_total_iterations=getattr(args, "max_total_iterations", 256),
145
+ )
146
+ if result["status"] != "completed":
147
+ print("\n".join(_noncompleted_summary_lines(result)), file=sys.stderr, flush=True)
148
+ print(json.dumps(_jsonify(result), indent=2))
149
+ return 0 if result["status"] == "completed" else 1
150
+
151
+
152
+ def main() -> int:
153
+ parser = argparse.ArgumentParser(
154
+ description=(
155
+ "Run a plain researcher project folder through DeepLoop until completion or a true operator boundary. "
156
+ "This command handles init + bounded start/resume loops for you."
157
+ ),
158
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
159
+ )
160
+ _add_run_args(parser)
161
+ args = parser.parse_args()
162
+ return _run_project(args)
163
+
164
+
165
+ __all__ = ["main", "_add_run_args", "_run_project"]
@@ -7,7 +7,7 @@ from typing import Any, Mapping
7
7
  def management_commands(mission_state_path: Path) -> dict[str, str]:
8
8
  mission_state_arg = str(mission_state_path)
9
9
  return {
10
- name: f"python scripts/mission/manage_mission.py {name} --mission-state {mission_state_arg}"
10
+ name: f"deeploop {name} --mission-state {mission_state_arg}"
11
11
  for name in ("status", "logs", "decisions", "inbox", "resume", "retry", "reroute", "triage", "stop")
12
12
  }
13
13
 
@@ -130,8 +130,8 @@ def operator_console_snapshot(
130
130
 
131
131
  headline = "STOPPED — DeepLoop is not currently running."
132
132
  summary = "No operator-facing mission summary is available yet."
133
- recommendation = "Run status and logs to inspect the current mission state."
134
- continue_summary = "Start or resume the mission once the desired next step is clear."
133
+ recommendation = "Run `deeploop status` or `deeploop logs` to inspect the current mission state."
134
+ continue_summary = "Start or resume once the next step is clear."
135
135
  gate_class = "none"
136
136
  gate_detail = None
137
137
  stop_reason = None
@@ -184,15 +184,15 @@ def operator_console_snapshot(
184
184
  ] or alternatives
185
185
  gate_class = str(blocker.get("kind") or blocker.get("gate") or "operator-review")
186
186
  gate_detail = str(blocker.get("risk_class") or blocker.get("label") or gate_class)
187
- headline = "BLOCKED — operator action is required before DeepLoop can continue."
187
+ headline = "BLOCKED — review the request, then resume when ready."
188
188
  summary = str(current_request.get("summary") or blocker.get("reason") or "DeepLoop opened the operator inbox.")
189
189
  recommendation = str(
190
190
  recommendation_payload.get("summary")
191
- or "Review the request, make the smallest safe change, then resume autopilot."
191
+ or "Review the request, make the smallest safe change, then resume."
192
192
  )
193
193
  stop_reason = str(blocker.get("reason") or failures.get("completion_reason") or summary)
194
194
  requires_action = True
195
- continue_summary = "Review the inbox, make the requested change, optionally record retry/reroute feedback, then resume."
195
+ continue_summary = "Open the inbox, fix or reroute the blocked step, optionally record feedback, then resume."
196
196
  next_commands = [
197
197
  *(
198
198
  [
@@ -234,7 +234,7 @@ def operator_console_snapshot(
234
234
  if isinstance(current_response, Mapping):
235
235
  action = str(current_response.get("action") or "operator-action")
236
236
  continue_summary = (
237
- f"Operator feedback `{action}` is already recorded. Finish the requested change, then resume autopilot."
237
+ f"Operator feedback `{action}` is already recorded. Finish the change, then resume."
238
238
  )
239
239
  next_commands = [
240
240
  {
@@ -390,7 +390,7 @@ def operator_console_snapshot(
390
390
  or failures.get("last_blocker")
391
391
  or "The detached mission process exited or has not started yet."
392
392
  )
393
- recommendation = "Inspect status, logs, and decisions, address the blocker honestly, then resume if more work is needed."
393
+ recommendation = "Inspect status, logs, and decisions, then resume only after the blocker is understood."
394
394
  continue_summary = "Resume only after the blocker is understood and the next step is safe."
395
395
  requires_action = mission_status in {"blocked", "failed"}
396
396
  next_commands = [