agentic-dev-loop 0.14.5__tar.gz → 0.15.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. {agentic_dev_loop-0.14.5/src/agentic_dev_loop.egg-info → agentic_dev_loop-0.15.0}/PKG-INFO +31 -25
  2. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/README.md +30 -24
  3. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/pyproject.toml +1 -1
  4. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/cli.py +169 -20
  5. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/hostboundary.py +1 -2
  6. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/doctor.py +8 -4
  7. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/init.py +10 -12
  8. agentic_dev_loop-0.15.0/src/agentic_dev_loop/engine/onboarding/templates/env.example +13 -0
  9. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/templates.py +1 -1
  10. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/upgrade.py +8 -4
  11. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/run_status.py +6 -2
  12. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/viz/runs_view.py +11 -7
  13. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/viz/server.py +21 -6
  14. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0/src/agentic_dev_loop.egg-info}/PKG-INFO +31 -25
  15. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -3
  16. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_init.py +1 -1
  17. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_templates.py +0 -22
  18. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_cli.py +189 -11
  19. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_hostboundary.py +2 -3
  20. agentic_dev_loop-0.15.0/tests/test_source_resolution.py +36 -0
  21. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit12_reporting.py +66 -6
  22. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_viz_demo.py +1 -1
  23. agentic_dev_loop-0.14.5/src/agentic_dev_loop/engine/onboarding/templates/env.example +0 -11
  24. agentic_dev_loop-0.14.5/src/agentic_dev_loop/engine/onboarding/templates/trigger-agentic-dev-loop.sh +0 -97
  25. agentic_dev_loop-0.14.5/src/agentic_dev_loop/viz/__main__.py +0 -59
  26. agentic_dev_loop-0.14.5/tests/test_source_resolution.py +0 -62
  27. agentic_dev_loop-0.14.5/tests/test_trigger_script.py +0 -306
  28. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/LICENSE +0 -0
  29. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/setup.cfg +0 -0
  30. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/__init__.py +0 -0
  31. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/__init__.py +0 -0
  32. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/config.py +0 -0
  33. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/failure.py +0 -0
  34. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/paths.py +0 -0
  35. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/profiles/__init__.py +0 -0
  36. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/profiles/data/dotnet-node.yaml +0 -0
  37. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/profiles/data/python.yaml +0 -0
  38. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/results.py +0 -0
  39. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/core/verdict.py +0 -0
  40. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/__init__.py +0 -0
  41. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/actions.py +0 -0
  42. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
  43. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
  44. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/agents.py +0 -0
  45. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/allowlist.py +0 -0
  46. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
  47. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
  48. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
  49. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/completion.py +0 -0
  50. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/containers.py +0 -0
  51. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/copilot_auth.py +0 -0
  52. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/deps.py +0 -0
  53. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/dryrun.py +0 -0
  54. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
  55. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
  56. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
  57. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
  58. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/forbidden.py +0 -0
  59. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/graph.py +0 -0
  60. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/isolation.py +0 -0
  61. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/llm.py +0 -0
  62. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/loaders.py +0 -0
  63. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/mounts.py +0 -0
  64. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/__init__.py +0 -0
  65. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/checks.py +0 -0
  66. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/recipes/dotnet-node.yaml +0 -0
  67. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/recipes/python.yaml +0 -0
  68. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/recipes.py +0 -0
  69. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/templates/dev.agent.md +0 -0
  70. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/templates/qa.agent.md +0 -0
  71. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/onboarding/templates/review.agent.md +0 -0
  72. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/outputs.py +0 -0
  73. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/presets.py +0 -0
  74. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/proc.py +0 -0
  75. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/provider_wire.py +0 -0
  76. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/registry.py +0 -0
  77. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/run_status_command.md +0 -0
  78. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
  79. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
  80. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/secrets.py +0 -0
  81. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/stages.py +0 -0
  82. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
  83. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/engine/sync_back.py +0 -0
  84. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/py.typed +0 -0
  85. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/reporting/__init__.py +0 -0
  86. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/reporting/metrics.py +0 -0
  87. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/reporting/render.py +0 -0
  88. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/reporting/sources.py +0 -0
  89. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/viz/__init__.py +0 -0
  90. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/viz/layout.py +0 -0
  91. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop/viz/page.py +0 -0
  92. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
  93. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
  94. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
  95. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
  96. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_029_merge_on_conflict.py +0 -0
  97. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_033_brief_step.py +0 -0
  98. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_035_finalize_nudge.py +0 -0
  99. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
  100. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_041_brief_coverage.py +0 -0
  101. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_046_brief_prompt.py +0 -0
  102. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_cli.py +0 -0
  103. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_doctor.py +0 -0
  104. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_profile_loading.py +0 -0
  105. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_profiles.py +0 -0
  106. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_recipes.py +0 -0
  107. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_schema_lock.py +0 -0
  108. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_055_upgrade.py +0 -0
  109. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_actions.py +0 -0
  110. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_agent_error_guide.py +0 -0
  111. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_agents.py +0 -0
  112. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_aidlc.py +0 -0
  113. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_build_viz_page.py +0 -0
  114. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_config.py +0 -0
  115. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_containers.py +0 -0
  116. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_copilot_auth.py +0 -0
  117. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_copilot_cli.py +0 -0
  118. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_deps.py +0 -0
  119. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_dry_run.py +0 -0
  120. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_e2e_fixtures.py +0 -0
  121. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_egress_proxy.py +0 -0
  122. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_graph.py +0 -0
  123. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_hostboundary_integration.py +0 -0
  124. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_isolation.py +0 -0
  125. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_isolation_integration.py +0 -0
  126. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_isolation_pbt.py +0 -0
  127. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_llm.py +0 -0
  128. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_loaders.py +0 -0
  129. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_module_contract.py +0 -0
  130. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_outputs.py +0 -0
  131. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_outputs_pbt.py +0 -0
  132. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_proc.py +0 -0
  133. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_provider_wire.py +0 -0
  134. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_publish.py +0 -0
  135. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_qa_prompt.py +0 -0
  136. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_registry.py +0 -0
  137. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_repo_ascii.py +0 -0
  138. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_results.py +0 -0
  139. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_run_status.py +0 -0
  140. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_runs_js_filters.py +0 -0
  141. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_runs_js_key_stats.py +0 -0
  142. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_runs_js_metrics.py +0 -0
  143. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_runs_layout.py +0 -0
  144. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_runs_layout_key_stats.py +0 -0
  145. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_sdk_compat.py +0 -0
  146. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_secrets.py +0 -0
  147. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_secrets_integration.py +0 -0
  148. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_secrets_pipeline.py +0 -0
  149. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_stages.py +0 -0
  150. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_step_workspace.py +0 -0
  151. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_sync_back.py +0 -0
  152. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit11.py +0 -0
  153. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit11_pbt.py +0 -0
  154. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit13_runs_viz.py +0 -0
  155. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit5_config.py +0 -0
  156. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit5_pbt.py +0 -0
  157. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_unit5_pure.py +0 -0
  158. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_verdict.py +0 -0
  159. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_viz.py +0 -0
  160. {agentic_dev_loop-0.14.5 → agentic_dev_loop-0.15.0}/tests/test_viz_layout.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-dev-loop
3
- Version: 0.14.5
3
+ Version: 0.15.0
4
4
  Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
5
5
  Author: Luke Wilson
6
6
  License-Expression: Apache-2.0
@@ -126,8 +126,13 @@ agentic-dev-loop agentic-dev-loop/pipeline.yaml # run it
126
126
  | `--dry-run` | Full load-and-validate pass, then print the resolved plan. No LLM, no Docker, no state writes, no API key. Exit `0` on a clean load. |
127
127
  | `--resume <thread-id>` | Continue the latest checkpoint of a previous run (crash, Ctrl-C, exhaustion) with all accumulated notes intact. |
128
128
  | `--max-attempts <n>` | Override the pipeline's `max_attempts`. |
129
+ | `--env <file>` | Load secrets from a host env file outside the workspace. Optional: the process environment is the default, a named-but-missing file is a loud error, and values already set in the environment win. |
129
130
  | `--no-viz` / `--viz-port <port>` | Suppress the live graph view / set a preferred port (default 8321; falls back to a free port when busy). |
130
131
 
132
+ `PIPELINE` is optional and defaults to `agentic-dev-loop/pipeline.yaml`
133
+ (relative to the current directory). Run flags without a positional use that
134
+ default; a missing default fails loudly instead of falling back.
135
+
131
136
  Exit code is `0` on pipeline success, `1` otherwise.
132
137
 
133
138
  Other commands:
@@ -136,18 +141,19 @@ Other commands:
136
141
  mermaid flowchart with the current step highlighted, reading the run-state
137
142
  checkpoint database directly. `run-status --install` installs the bundled
138
143
  `/run-status` command into OpenCode.
139
- - `agentic-dev-loop report [<run-id>]` renders accumulated run history as
140
- ASCII markdown: an aggregate dashboard by default (loop health, TDD,
144
+ - `agentic-dev-loop report` serves the **historical runs view** in the
145
+ browser (default port 8321, falling back to a free port when busy; blocks
146
+ until ctrl+c and prints the URL). It reads the same run records as the
147
+ markdown report and lists past runs with since / until / status filters,
148
+ an aggregate metrics panel, and a per-run detail page carrying the brief,
149
+ implementation summary, review findings, and QA report. The live viz also
150
+ links to it from the **History** button in the graph page header (or
151
+ `/runs`).
152
+ - `agentic-dev-loop report --markdown [<run-id>]` renders the same history
153
+ as ASCII markdown instead: an aggregate dashboard (loop health, TDD,
141
154
  review, and QA metrics with provenance labels) or a deep dive for one
142
155
  12-hex run directory. `--since` / `--until` / `--status` filter the set.
143
- Reporting is strictly read-only.
144
- - The live viz also serves a **historical runs view**: click **History** in
145
- the graph page header (or open `/runs`), or launch it standalone with
146
- `python -m agentic_dev_loop.viz --history`, which needs no pipeline file
147
- (default port 8321, falling back to a free port when busy). It lists past
148
- runs with since / until / status filters, an aggregate metrics panel, and
149
- a per-run detail page carrying the brief, implementation summary, review
150
- findings, and QA report.
156
+ `--markdown` cannot be combined with `--port`.
151
157
  - `agentic-dev-loop containers` inspects the engine's sandbox containers and
152
158
  networks from the host; `containers --reap` removes registry-owned orphans
153
159
  whose owner process is dead. A SIGTERM to a running pipeline still closes
@@ -489,20 +495,20 @@ agentic-dev-loop init --profile python # or: --profile dotnet-node
489
495
  ```
490
496
 
491
497
  `init` writes the onboarding surface from a bundled toolchain profile:
492
- `agentic-dev-loop/pipeline.yaml`, the three agent files, an executable
493
- `trigger-agentic-dev-loop.sh`, `agentic-dev-loop/.engine-version` (the exact
494
- installed engine version), any missing premise files, gitignore additions,
495
- and an env-file template. It detects solution files, `package.json`
496
- directories, lockfiles, README, and AGENTS.md, asks only what detection
497
- cannot answer, and refuses to overwrite an existing `agentic-dev-loop/`
498
- directory. A consumer-authored profile file can be passed by path instead of
499
- a bundled name.
500
-
501
- `agentic-dev-loop doctor --fast` is the per-run gate the trigger runs first:
502
- hard failures abort the run (engine pin mismatch, engine runtime
498
+ `agentic-dev-loop/pipeline.yaml`, the three agent files,
499
+ `agentic-dev-loop/.engine-version` (the exact installed engine version), any
500
+ missing premise files, gitignore additions, and an env-file template. It
501
+ detects solution files, `package.json` directories, lockfiles, README, and
502
+ AGENTS.md, asks only what detection cannot answer, and refuses to overwrite
503
+ an existing `agentic-dev-loop/` directory. A consumer-authored profile file
504
+ can be passed by path instead of a bundled name.
505
+
506
+ `agentic-dev-loop doctor --fast` probes the host and repo before you run:
507
+ hard failures stop you here (engine pin mismatch, engine runtime
503
508
  availability, API version, git repo, `.env*` files); warnings print and
504
- continue. On a hard failure the trigger runs `agentic-dev-loop upgrade`
505
- exactly once, then the run fails hard if doctor still fails.
509
+ continue. `agentic-dev-loop upgrade` installs the latest engine release and
510
+ rewrites the pin, so the host install and the committed pin converge in one
511
+ explicit action. Run both yourself; the CLI never runs them for you.
506
512
 
507
513
  A consumer repo needs a pipeline file and the agent files it names, both
508
514
  committed before the first run. `init` writes them; the layout is:
@@ -615,7 +621,7 @@ export OPENAI_API_KEY=... # set your LLM key in the host env
615
621
  python -m pytest tests/ -q # fast suite (in-repo .venv is for tests only)
616
622
  python -m pytest tests/ -q -m "not docker" # skip engine-dependent tests
617
623
  agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pipeline
618
- ./run-demo.sh # viz demo - scripted run replay, no pipeline needed
624
+ .venv-sandbox/bin/python tests/smoke/viz_demo.py # viz demo - scripted replay, no pipeline needed
619
625
  ```
620
626
 
621
627
  - `setup-venv.sh` builds the throwaway `.venv` for local `pytest` runs. The
@@ -81,8 +81,13 @@ agentic-dev-loop agentic-dev-loop/pipeline.yaml # run it
81
81
  | `--dry-run` | Full load-and-validate pass, then print the resolved plan. No LLM, no Docker, no state writes, no API key. Exit `0` on a clean load. |
82
82
  | `--resume <thread-id>` | Continue the latest checkpoint of a previous run (crash, Ctrl-C, exhaustion) with all accumulated notes intact. |
83
83
  | `--max-attempts <n>` | Override the pipeline's `max_attempts`. |
84
+ | `--env <file>` | Load secrets from a host env file outside the workspace. Optional: the process environment is the default, a named-but-missing file is a loud error, and values already set in the environment win. |
84
85
  | `--no-viz` / `--viz-port <port>` | Suppress the live graph view / set a preferred port (default 8321; falls back to a free port when busy). |
85
86
 
87
+ `PIPELINE` is optional and defaults to `agentic-dev-loop/pipeline.yaml`
88
+ (relative to the current directory). Run flags without a positional use that
89
+ default; a missing default fails loudly instead of falling back.
90
+
86
91
  Exit code is `0` on pipeline success, `1` otherwise.
87
92
 
88
93
  Other commands:
@@ -91,18 +96,19 @@ Other commands:
91
96
  mermaid flowchart with the current step highlighted, reading the run-state
92
97
  checkpoint database directly. `run-status --install` installs the bundled
93
98
  `/run-status` command into OpenCode.
94
- - `agentic-dev-loop report [<run-id>]` renders accumulated run history as
95
- ASCII markdown: an aggregate dashboard by default (loop health, TDD,
99
+ - `agentic-dev-loop report` serves the **historical runs view** in the
100
+ browser (default port 8321, falling back to a free port when busy; blocks
101
+ until ctrl+c and prints the URL). It reads the same run records as the
102
+ markdown report and lists past runs with since / until / status filters,
103
+ an aggregate metrics panel, and a per-run detail page carrying the brief,
104
+ implementation summary, review findings, and QA report. The live viz also
105
+ links to it from the **History** button in the graph page header (or
106
+ `/runs`).
107
+ - `agentic-dev-loop report --markdown [<run-id>]` renders the same history
108
+ as ASCII markdown instead: an aggregate dashboard (loop health, TDD,
96
109
  review, and QA metrics with provenance labels) or a deep dive for one
97
110
  12-hex run directory. `--since` / `--until` / `--status` filter the set.
98
- Reporting is strictly read-only.
99
- - The live viz also serves a **historical runs view**: click **History** in
100
- the graph page header (or open `/runs`), or launch it standalone with
101
- `python -m agentic_dev_loop.viz --history`, which needs no pipeline file
102
- (default port 8321, falling back to a free port when busy). It lists past
103
- runs with since / until / status filters, an aggregate metrics panel, and
104
- a per-run detail page carrying the brief, implementation summary, review
105
- findings, and QA report.
111
+ `--markdown` cannot be combined with `--port`.
106
112
  - `agentic-dev-loop containers` inspects the engine's sandbox containers and
107
113
  networks from the host; `containers --reap` removes registry-owned orphans
108
114
  whose owner process is dead. A SIGTERM to a running pipeline still closes
@@ -444,20 +450,20 @@ agentic-dev-loop init --profile python # or: --profile dotnet-node
444
450
  ```
445
451
 
446
452
  `init` writes the onboarding surface from a bundled toolchain profile:
447
- `agentic-dev-loop/pipeline.yaml`, the three agent files, an executable
448
- `trigger-agentic-dev-loop.sh`, `agentic-dev-loop/.engine-version` (the exact
449
- installed engine version), any missing premise files, gitignore additions,
450
- and an env-file template. It detects solution files, `package.json`
451
- directories, lockfiles, README, and AGENTS.md, asks only what detection
452
- cannot answer, and refuses to overwrite an existing `agentic-dev-loop/`
453
- directory. A consumer-authored profile file can be passed by path instead of
454
- a bundled name.
455
-
456
- `agentic-dev-loop doctor --fast` is the per-run gate the trigger runs first:
457
- hard failures abort the run (engine pin mismatch, engine runtime
453
+ `agentic-dev-loop/pipeline.yaml`, the three agent files,
454
+ `agentic-dev-loop/.engine-version` (the exact installed engine version), any
455
+ missing premise files, gitignore additions, and an env-file template. It
456
+ detects solution files, `package.json` directories, lockfiles, README, and
457
+ AGENTS.md, asks only what detection cannot answer, and refuses to overwrite
458
+ an existing `agentic-dev-loop/` directory. A consumer-authored profile file
459
+ can be passed by path instead of a bundled name.
460
+
461
+ `agentic-dev-loop doctor --fast` probes the host and repo before you run:
462
+ hard failures stop you here (engine pin mismatch, engine runtime
458
463
  availability, API version, git repo, `.env*` files); warnings print and
459
- continue. On a hard failure the trigger runs `agentic-dev-loop upgrade`
460
- exactly once, then the run fails hard if doctor still fails.
464
+ continue. `agentic-dev-loop upgrade` installs the latest engine release and
465
+ rewrites the pin, so the host install and the committed pin converge in one
466
+ explicit action. Run both yourself; the CLI never runs them for you.
461
467
 
462
468
  A consumer repo needs a pipeline file and the agent files it names, both
463
469
  committed before the first run. `init` writes them; the layout is:
@@ -570,7 +576,7 @@ export OPENAI_API_KEY=... # set your LLM key in the host env
570
576
  python -m pytest tests/ -q # fast suite (in-repo .venv is for tests only)
571
577
  python -m pytest tests/ -q -m "not docker" # skip engine-dependent tests
572
578
  agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pipeline
573
- ./run-demo.sh # viz demo - scripted run replay, no pipeline needed
579
+ .venv-sandbox/bin/python tests/smoke/viz_demo.py # viz demo - scripted replay, no pipeline needed
574
580
  ```
575
581
 
576
582
  - `setup-venv.sh` builds the throwaway `.venv` for local `pytest` runs. The
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentic-dev-loop"
7
- version = "0.14.5"
7
+ version = "0.15.0"
8
8
  description = "Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -22,6 +22,31 @@ from .loaders import mark_plan_completed
22
22
  from .registry import Registry, default_registry, load_extensions
23
23
 
24
24
 
25
+ _DEFAULT_PIPELINE = Path("agentic-dev-loop") / "pipeline.yaml"
26
+
27
+ _TOP_HELP = """\
28
+ usage: agentic-dev-loop [PIPELINE] [--resume THREAD_ID] [--max-attempts N]
29
+ [--no-viz] [--viz-port PORT] [--dry-run] [--version]
30
+
31
+ Run an OpenHands agent pipeline defined in YAML. PIPELINE defaults to
32
+ agentic-dev-loop/pipeline.yaml; run `agentic-dev-loop <PIPELINE> --help`
33
+ for loader-contributed options (e.g. --plan, --aidlc-unit).
34
+
35
+ commands:
36
+ containers Inspect engine sandbox containers and networks.
37
+ copilot-login Run the GitHub device flow and store the Copilot OAuth token.
38
+ copilot-models List the Copilot models available to this token's tier.
39
+ report Serve the run-history browser view (--markdown for text).
40
+ run-status Report the latest agentic-dev-loop run.
41
+ init Write agentic-dev-loop pipeline and agent files.
42
+ doctor Probe this host and repo for onboarding prerequisites.
43
+ upgrade Install the latest engine release and rewrite the project pin.
44
+ help Show this list.
45
+
46
+ Run `agentic-dev-loop <command> --help` for per-command options.
47
+ """
48
+
49
+
25
50
  _sigterm_in_progress = False
26
51
 
27
52
 
@@ -79,8 +104,9 @@ def _core_parser() -> argparse.ArgumentParser:
79
104
  "Document-loader flags contributed by the pipeline's "
80
105
  "extensions appear once PIPELINE is known - see "
81
106
  "`agentic-dev-loop PIPELINE --help`.")
82
- parser.add_argument("pipeline", type=Path,
83
- help="path to the pipeline YAML")
107
+ parser.add_argument("pipeline", type=Path, nargs="?", default=None,
108
+ help="path to the pipeline YAML (default: "
109
+ "agentic-dev-loop/pipeline.yaml)")
84
110
  parser.add_argument("--resume", metavar="THREAD_ID", default=None,
85
111
  help="resume a checkpointed run by thread id")
86
112
  parser.add_argument("--max-attempts", type=int, default=None,
@@ -96,6 +122,9 @@ def _core_parser() -> argparse.ArgumentParser:
96
122
  help="validate the pipeline and print a summary plan "
97
123
  "without executing anything (no LLM, no "
98
124
  "sandbox, no state writes)")
125
+ parser.add_argument("--env", metavar="FILE", default=None,
126
+ help="load secrets from a host env file outside the "
127
+ "workspace (default: the process environment)")
99
128
  _add_version_flag(parser)
100
129
  return parser
101
130
 
@@ -164,15 +193,19 @@ def _token_path(value: str | None) -> Path:
164
193
  return Path(value).expanduser() if value else TOKEN_PATH.expanduser()
165
194
 
166
195
 
167
- def _run_copilot_login(argv: list[str]) -> int:
196
+ def _copilot_login_parser() -> argparse.ArgumentParser:
168
197
  parser = argparse.ArgumentParser(
169
198
  prog="agentic-dev-loop copilot-login",
170
199
  description="Run the GitHub device flow and store the Copilot OAuth "
171
- "token (~/.agentic-dev-loop/auth/copilot.json, mode 600).")
200
+ "token.")
172
201
  parser.add_argument("--token-file", default=None,
173
202
  help="token path (default: "
174
203
  "~/.agentic-dev-loop/auth/copilot.json)")
175
- args = parser.parse_args(argv)
204
+ return parser
205
+
206
+
207
+ def _run_copilot_login(argv: list[str]) -> int:
208
+ args = _copilot_login_parser().parse_args(argv)
176
209
  path = _token_path(args.token_file)
177
210
  try:
178
211
  login(token_path=path)
@@ -183,7 +216,7 @@ def _run_copilot_login(argv: list[str]) -> int:
183
216
  return 0
184
217
 
185
218
 
186
- def _run_copilot_models(argv: list[str]) -> int:
219
+ def _copilot_models_parser() -> argparse.ArgumentParser:
187
220
  parser = argparse.ArgumentParser(
188
221
  prog="agentic-dev-loop copilot-models",
189
222
  description="List the Copilot models available to this token's tier.")
@@ -192,7 +225,11 @@ def _run_copilot_models(argv: list[str]) -> int:
192
225
  "~/.agentic-dev-loop/auth/copilot.json)")
193
226
  parser.add_argument("--json", action="store_true",
194
227
  help="emit the model list as JSON")
195
- args = parser.parse_args(argv)
228
+ return parser
229
+
230
+
231
+ def _run_copilot_models(argv: list[str]) -> int:
232
+ args = _copilot_models_parser().parse_args(argv)
196
233
  try:
197
234
  models = list_copilot_models(read_token(_token_path(args.token_file)))
198
235
  except CopilotAuthError as e:
@@ -209,11 +246,16 @@ def _run_copilot_models(argv: list[str]) -> int:
209
246
  def _report_parser() -> argparse.ArgumentParser:
210
247
  parser = argparse.ArgumentParser(
211
248
  prog="agentic-dev-loop report",
212
- description="Report accumulated agentic-dev-loop run history as "
213
- "read-only markdown.")
249
+ description="Serve the run-history browser view (--markdown for text).")
214
250
  parser.add_argument("run_id", nargs="?", default=None,
215
251
  help="12-hex run dir name for a deep dive "
216
- "(default: aggregate report)")
252
+ "(markdown mode only)")
253
+ parser.add_argument("--markdown", action="store_true",
254
+ help="render read-only markdown instead of serving "
255
+ "the browser view")
256
+ parser.add_argument("--port", type=int, default=None,
257
+ help="server port (default: 8321; falls back to a "
258
+ "free port when busy)")
217
259
  parser.add_argument("--since", default=None,
218
260
  help="only threads starting at or after this ISO "
219
261
  "datetime")
@@ -234,11 +276,28 @@ def _report_parser() -> argparse.ArgumentParser:
234
276
 
235
277
 
236
278
  def _run_report(argv: list[str]) -> int:
279
+ args = _report_parser().parse_args(argv)
280
+ if args.markdown:
281
+ if args.port is not None:
282
+ print("report: --markdown and --port are mutually exclusive",
283
+ file=sys.stderr)
284
+ return 2
285
+ return _render_report(args)
286
+ markdown_only = [flag for flag, value in (
287
+ ("run_id", args.run_id), ("--since", args.since),
288
+ ("--until", args.until), ("--status", args.status)) if value]
289
+ if markdown_only:
290
+ print(f"report: {markdown_only[0]} requires --markdown",
291
+ file=sys.stderr)
292
+ return 2
293
+ return _serve_report(args)
294
+
295
+
296
+ def _render_report(args) -> int:
237
297
  from agentic_dev_loop.reporting import (
238
298
  apply_filters, build_run_records, discover, find_run_dir,
239
299
  pure_metrics, read_audit, read_dir, render_markdown, runs_root)
240
300
 
241
- args = _report_parser().parse_args(argv)
242
301
  root = runs_root(args.runs_root)
243
302
  notice = None
244
303
  if args.run_id is not None:
@@ -271,6 +330,78 @@ def _run_report(argv: list[str]) -> int:
271
330
  return 0
272
331
 
273
332
 
333
+ def _serve_report(args) -> int:
334
+ from agentic_dev_loop.viz import serve_history
335
+
336
+ port = 8321 if args.port is None else args.port
337
+ try:
338
+ httpd, _thread = serve_history(port, runs_root=args.runs_root,
339
+ audit_dir=args.audit_dir)
340
+ except OSError as exc:
341
+ print(f"report: {exc}", file=sys.stderr)
342
+ return 1
343
+ bound = httpd.server_address[1]
344
+ url = f"http://127.0.0.1:{bound}"
345
+ print(f"Run history viz: {url}", flush=True)
346
+ if port and bound != port:
347
+ print(f"report port {port} busy - serving on {url}", flush=True)
348
+ try:
349
+ _wait_for_interrupt()
350
+ except KeyboardInterrupt:
351
+ pass
352
+ finally:
353
+ httpd.shutdown()
354
+ return 0
355
+
356
+
357
+ def _probe_parser() -> argparse.ArgumentParser:
358
+ """Phase-1 parser: find PIPELINE (or the default) without loading any
359
+ extension or SDK module."""
360
+ probe = argparse.ArgumentParser(add_help=False)
361
+ probe.add_argument("pipeline", type=Path, nargs="?")
362
+ probe.add_argument("--resume", default=None)
363
+ probe.add_argument("--max-attempts", default=None)
364
+ probe.add_argument("--viz-port", default=None)
365
+ probe.add_argument("--env", default=None)
366
+ probe.add_argument("--no-viz", action="store_true")
367
+ probe.add_argument("--dry-run", action="store_true")
368
+ _add_version_flag(probe)
369
+ return probe
370
+
371
+
372
+ def _load_env_file(path: Path) -> str | None:
373
+ """Load KEY=VALUE lines from a host file into the process environment.
374
+
375
+ The file must live outside the workspace (doctor refuses workspace
376
+ ``.env*`` files; the run path uses the same boundary). Values already set
377
+ in the environment win, so a file never overrides the operator's shell.
378
+ Returns an error message, or ``None`` on success.
379
+ """
380
+ target = path.expanduser().resolve()
381
+ workspace = Path.cwd().resolve()
382
+ if target == workspace or target.is_relative_to(workspace):
383
+ return (f"--env file {target} is inside the workspace {workspace}; "
384
+ "secret files must live outside the workspace")
385
+ if not target.is_file():
386
+ return f"--env file not found: {target}"
387
+ for raw in target.read_text(encoding="utf-8").splitlines():
388
+ line = raw.strip()
389
+ if not line or line.startswith("#"):
390
+ continue
391
+ if line.startswith("export "):
392
+ line = line[len("export "):].strip()
393
+ key, sep, value = line.partition("=")
394
+ key = key.strip()
395
+ if not sep or not key:
396
+ continue
397
+ value = value.strip()
398
+ if len(value) >= 2 and value[0] == value[-1] and value[0] in "'\"":
399
+ value = value[1:-1]
400
+ if key not in os.environ:
401
+ os.environ[key] = value
402
+ return None
403
+
404
+
274
405
  def build_parser(cfg_path) -> argparse.ArgumentParser:
275
406
  """The full parser for one pipeline: core flags + loader-contributed."""
276
407
  registry, _ = _registry_for(cfg_path)
@@ -285,6 +416,12 @@ def main(argv: list[str] | None = None, *, keep_alive: bool = True) -> int:
285
416
  argv = sys.argv[1:]
286
417
  else:
287
418
  argv = list(argv)
419
+ if argv and argv[0] == "help":
420
+ if len(argv) > 1:
421
+ print("error: help takes no arguments", file=sys.stderr)
422
+ return 2
423
+ print(_TOP_HELP)
424
+ return 0
288
425
  if argv and argv[0] == "containers":
289
426
  return _run_containers(argv[1:])
290
427
  if argv and argv[0] == "copilot-login":
@@ -305,20 +442,32 @@ def main(argv: list[str] | None = None, *, keep_alive: bool = True) -> int:
305
442
  if argv and argv[0] == "upgrade":
306
443
  from .onboarding.upgrade import run_upgrade
307
444
  return run_upgrade(argv[1:])
308
- probe = argparse.ArgumentParser(add_help=False)
309
- probe.add_argument("pipeline", type=Path, nargs="?")
310
- _add_version_flag(probe)
311
- known, _ = probe.parse_known_args(argv)
445
+ if not argv:
446
+ print(_TOP_HELP)
447
+ return 0
448
+ known, _ = _probe_parser().parse_known_args(argv)
312
449
  if known.pipeline is None:
313
- # No pipeline → the extension surface is unknowable; the core parser
314
- # handles --help and the missing-positional error itself (both exit).
315
- _core_parser().parse_args(argv)
316
- return 2 # unreachable - parse_args exits first
317
- registry, cfg = _registry_for(known.pipeline)
450
+ if "-h" in argv or "--help" in argv:
451
+ print(_TOP_HELP)
452
+ return 0
453
+ if not _DEFAULT_PIPELINE.is_file():
454
+ print(f"agentic-dev-loop: no pipeline at {_DEFAULT_PIPELINE} "
455
+ "and none given", file=sys.stderr)
456
+ return 1
457
+ pipeline = _DEFAULT_PIPELINE
458
+ else:
459
+ pipeline = known.pipeline
460
+ if known.env is not None:
461
+ error = _load_env_file(Path(known.env))
462
+ if error is not None:
463
+ print(f"agentic-dev-loop: {error}", file=sys.stderr)
464
+ return 1
465
+ registry, cfg = _registry_for(pipeline)
318
466
  parser = _core_parser()
319
467
  for loader in registry.document_loaders:
320
468
  loader.add_cli_args(parser)
321
469
  args = parser.parse_args(argv)
470
+ args.pipeline = pipeline
322
471
  if args.dry_run:
323
472
  from .dryrun import dry_run
324
473
  return dry_run(args.pipeline, args, registry)
@@ -32,8 +32,7 @@ if TYPE_CHECKING:
32
32
  # the dogfood pipeline and the consumer repo use); the other tooling paths are config- or
33
33
  # pipeline-file-relative.
34
34
  TOOLING_DIR_NAMES = ("aidlc-docs", "tools")
35
- TOOLING_FILE_NAMES = ("trigger-agentic-dev-loop.sh",
36
- "agentic-dev-loop/.engine-version")
35
+ TOOLING_FILE_NAMES = ("agentic-dev-loop/.engine-version",)
37
36
 
38
37
 
39
38
  class HostBoundaryError(RuntimeError):
@@ -38,9 +38,7 @@ def _print_failures(checks: list[Check]) -> None:
38
38
  print(f" fix: {check.fix_text}")
39
39
 
40
40
 
41
- def run_doctor(argv: list[str], *, workspace: Path | None = None,
42
- probes: HostProbes | None = None,
43
- installed: str | None = None) -> int:
41
+ def _doctor_parser() -> argparse.ArgumentParser:
44
42
  parser = argparse.ArgumentParser(
45
43
  prog="agentic-dev-loop doctor",
46
44
  description="Probe this host and repo for onboarding prerequisites.")
@@ -49,7 +47,13 @@ def run_doctor(argv: list[str], *, workspace: Path | None = None,
49
47
  "round trip")
50
48
  parser.add_argument("--json", action="store_true",
51
49
  help="emit machine-readable JSON results")
52
- args = parser.parse_args(argv)
50
+ return parser
51
+
52
+
53
+ def run_doctor(argv: list[str], *, workspace: Path | None = None,
54
+ probes: HostProbes | None = None,
55
+ installed: str | None = None) -> int:
56
+ args = _doctor_parser().parse_args(argv)
53
57
 
54
58
  root = Path(workspace or Path.cwd()).resolve()
55
59
  probes = probes or HostProbes()
@@ -308,11 +308,6 @@ def _write(root: Path, profile: Profile, pipeline: dict, texts: dict,
308
308
  (agents / f"{name}.agent.md").write_text(
309
309
  load_template(f"{name}.agent.md"), encoding="utf-8")
310
310
 
311
- trigger = root / "trigger-agentic-dev-loop.sh"
312
- trigger.write_text(load_template("trigger-agentic-dev-loop.sh"),
313
- encoding="utf-8")
314
- trigger.chmod(0o755)
315
-
316
311
  (out / ".engine-version").write_text(installed + "\n", encoding="utf-8")
317
312
 
318
313
  for premise in profile.premise_files:
@@ -368,11 +363,10 @@ def _answers(root: Path, profile_ref: str, yes: bool) -> dict:
368
363
  }
369
364
 
370
365
 
371
- def run_init(argv: list[str]) -> int:
366
+ def _init_parser() -> argparse.ArgumentParser:
372
367
  parser = argparse.ArgumentParser(
373
368
  prog="agentic-dev-loop init",
374
- description="Write agentic-dev-loop pipeline, agent, and trigger "
375
- "files for this repo.")
369
+ description="Write agentic-dev-loop pipeline and agent files.")
376
370
  parser.add_argument("--profile", default="python",
377
371
  help="bundled profile name or path (default: python)")
378
372
  parser.add_argument("--recipe", default=None,
@@ -382,7 +376,11 @@ def run_init(argv: list[str]) -> int:
382
376
  help="accept defaults without prompting")
383
377
  parser.add_argument("--dir", default=".",
384
378
  help="repo root to write into (default: .)")
385
- args = parser.parse_args(argv)
379
+ return parser
380
+
381
+
382
+ def run_init(argv: list[str]) -> int:
383
+ args = _init_parser().parse_args(argv)
386
384
  root = Path(args.dir).resolve()
387
385
  try:
388
386
  pipeline_path = root / "agentic-dev-loop" / "pipeline.yaml"
@@ -423,10 +421,10 @@ def _print_next_steps(pipeline_path: Path) -> None:
423
421
  Wrote {pipeline_path}
424
422
  Next steps:
425
423
  1. Export the LLM key named by api_key_env in the host environment
426
- (or set AGENTIC_DEV_LOOP_ENV_FILE to a host env file).
424
+ (or pass --env FILE, a host env file outside the workspace).
427
425
  2. Review agentic-dev-loop/pipeline.yaml and the agent files under
428
426
  agentic-dev-loop/sdk_agents/.
429
427
  3. Validate: agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run
430
- 4. Run: ./trigger-agentic-dev-loop.sh --plan <path> (or --aidlc-unit,
431
- or --resume).
428
+ 4. Run: agentic-dev-loop agentic-dev-loop/pipeline.yaml --plan <path>
429
+ (or --aidlc-unit, or --resume).
432
430
  """))
@@ -0,0 +1,13 @@
1
+ # Host environment file for agentic-dev-loop.
2
+ #
3
+ # Copy it outside the workspace (for example to
4
+ # ~/.config/<repo-name>/agentic-dev-loop.env) and fill in values there.
5
+ # Pass it to a run with --env FILE. Never commit a filled copy: the engine
6
+ # refuses a run when the workspace contains a .env* file, and this template
7
+ # carries no secret values. Values already set in the process environment
8
+ # win over the file.
9
+ #
10
+ # OPENAI_API_KEY=...
11
+ #
12
+ # Optional: override the toolchain image for a local build.
13
+ # AGENTIC_DEV_LOOP_DEV_IMAGE=...
@@ -1,4 +1,4 @@
1
- """Onboarding templates: agent prompts, the trigger script, env template."""
1
+ """Onboarding templates: agent prompts and the env template."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -24,13 +24,17 @@ def _resolve(name: str, env: dict | None) -> str | None:
24
24
  return shutil.which(name)
25
25
 
26
26
 
27
- def run_upgrade(argv: list[str], *, workspace: Path | None = None,
28
- env: dict | None = None) -> int:
27
+ def _upgrade_parser() -> argparse.ArgumentParser:
29
28
  parser = argparse.ArgumentParser(
30
29
  prog="agentic-dev-loop upgrade",
31
30
  description="Install the latest engine release and rewrite the "
32
- "project pin file to match.")
33
- parser.parse_args(argv)
31
+ "project pin.")
32
+ return parser
33
+
34
+
35
+ def run_upgrade(argv: list[str], *, workspace: Path | None = None,
36
+ env: dict | None = None) -> int:
37
+ _upgrade_parser().parse_args(argv)
34
38
 
35
39
  root = Path(workspace or Path.cwd()).resolve()
36
40
  pipx = _resolve("pipx", env)
@@ -311,7 +311,7 @@ def install_command(dest_dir: Path | None = None) -> Path:
311
311
  return target
312
312
 
313
313
 
314
- def _run_status(argv: list[str]) -> int:
314
+ def _run_status_parser() -> argparse.ArgumentParser:
315
315
  parser = argparse.ArgumentParser(
316
316
  prog="agentic-dev-loop run-status",
317
317
  description="Report the latest agentic-dev-loop run.",
@@ -330,7 +330,11 @@ def _run_status(argv: list[str]) -> int:
330
330
  help="install the /run-status OpenCode command into the consumer "
331
331
  "commands directory and exit",
332
332
  )
333
- args = parser.parse_args(argv)
333
+ return parser
334
+
335
+
336
+ def _run_status(argv: list[str]) -> int:
337
+ args = _run_status_parser().parse_args(argv)
334
338
 
335
339
  if args.install:
336
340
  target = install_command()