agentic-dev-loop 0.12.2__tar.gz → 0.13.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 (155) hide show
  1. agentic_dev_loop-0.13.0/PKG-INFO +642 -0
  2. agentic_dev_loop-0.13.0/README.md +597 -0
  3. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/pyproject.toml +1 -1
  4. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/cli.py +67 -0
  5. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/graph.py +2 -1
  6. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/provider_wire.py +7 -0
  7. agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/__init__.py +43 -0
  8. agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/metrics.py +593 -0
  9. agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/render.py +175 -0
  10. agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/sources.py +770 -0
  11. agentic_dev_loop-0.13.0/src/agentic_dev_loop/viz/page.py +9 -0
  12. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/server.py +7 -3
  13. agentic_dev_loop-0.13.0/src/agentic_dev_loop.egg-info/PKG-INFO +642 -0
  14. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/SOURCES.txt +5 -0
  15. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_cli.py +3 -1
  16. agentic_dev_loop-0.13.0/tests/test_unit12_reporting.py +309 -0
  17. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_viz.py +27 -2
  18. agentic_dev_loop-0.12.2/PKG-INFO +0 -936
  19. agentic_dev_loop-0.12.2/README.md +0 -891
  20. agentic_dev_loop-0.12.2/src/agentic_dev_loop/viz/page.py +0 -9
  21. agentic_dev_loop-0.12.2/src/agentic_dev_loop.egg-info/PKG-INFO +0 -936
  22. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/LICENSE +0 -0
  23. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/setup.cfg +0 -0
  24. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/__init__.py +0 -0
  25. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/__init__.py +0 -0
  26. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/config.py +0 -0
  27. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/failure.py +0 -0
  28. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/paths.py +0 -0
  29. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/__init__.py +0 -0
  30. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/data/dotnet-node.yaml +0 -0
  31. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/data/python.yaml +0 -0
  32. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/results.py +0 -0
  33. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/verdict.py +0 -0
  34. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/__init__.py +0 -0
  35. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/actions.py +0 -0
  36. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
  37. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
  38. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agents.py +0 -0
  39. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/allowlist.py +0 -0
  40. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
  41. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
  42. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
  43. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/completion.py +0 -0
  44. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/containers.py +0 -0
  45. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/copilot_auth.py +0 -0
  46. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/deps.py +0 -0
  47. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/dryrun.py +0 -0
  48. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
  49. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
  50. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
  51. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
  52. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/forbidden.py +0 -0
  53. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
  54. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/isolation.py +0 -0
  55. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/llm.py +0 -0
  56. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/loaders.py +0 -0
  57. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/mounts.py +0 -0
  58. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/__init__.py +0 -0
  59. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/checks.py +0 -0
  60. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/doctor.py +0 -0
  61. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/init.py +0 -0
  62. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes/dotnet-node.yaml +0 -0
  63. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes/python.yaml +0 -0
  64. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes.py +0 -0
  65. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/dev.agent.md +0 -0
  66. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/env.example +0 -0
  67. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/qa.agent.md +0 -0
  68. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/review.agent.md +0 -0
  69. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/trigger-agentic-dev-loop.sh +0 -0
  70. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates.py +0 -0
  71. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/upgrade.py +0 -0
  72. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/outputs.py +0 -0
  73. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/presets.py +0 -0
  74. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/proc.py +0 -0
  75. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/registry.py +0 -0
  76. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/run_status.py +0 -0
  77. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/run_status_command.md +0 -0
  78. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
  79. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
  80. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/secrets.py +0 -0
  81. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/stages.py +0 -0
  82. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
  83. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/sync_back.py +0 -0
  84. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/py.typed +0 -0
  85. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/__init__.py +0 -0
  86. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/__main__.py +0 -0
  87. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/layout.py +0 -0
  88. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
  89. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
  90. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
  91. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
  92. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_029_merge_on_conflict.py +0 -0
  93. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_033_brief_step.py +0 -0
  94. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_035_finalize_nudge.py +0 -0
  95. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
  96. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_041_brief_coverage.py +0 -0
  97. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_046_brief_prompt.py +0 -0
  98. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_cli.py +0 -0
  99. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_doctor.py +0 -0
  100. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_init.py +0 -0
  101. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_profile_loading.py +0 -0
  102. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_profiles.py +0 -0
  103. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_recipes.py +0 -0
  104. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_schema_lock.py +0 -0
  105. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_templates.py +0 -0
  106. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_upgrade.py +0 -0
  107. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_actions.py +0 -0
  108. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_agent_error_guide.py +0 -0
  109. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_agents.py +0 -0
  110. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_aidlc.py +0 -0
  111. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_build_viz_page.py +0 -0
  112. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_config.py +0 -0
  113. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_containers.py +0 -0
  114. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_copilot_auth.py +0 -0
  115. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_copilot_cli.py +0 -0
  116. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_deps.py +0 -0
  117. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_dry_run.py +0 -0
  118. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_e2e_fixtures.py +0 -0
  119. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_egress_proxy.py +0 -0
  120. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_graph.py +0 -0
  121. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_hostboundary.py +0 -0
  122. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_hostboundary_integration.py +0 -0
  123. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation.py +0 -0
  124. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation_integration.py +0 -0
  125. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation_pbt.py +0 -0
  126. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_llm.py +0 -0
  127. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_loaders.py +0 -0
  128. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_module_contract.py +0 -0
  129. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_outputs.py +0 -0
  130. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_outputs_pbt.py +0 -0
  131. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_proc.py +0 -0
  132. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_provider_wire.py +0 -0
  133. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_publish.py +0 -0
  134. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_qa_prompt.py +0 -0
  135. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_registry.py +0 -0
  136. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_repo_ascii.py +0 -0
  137. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_results.py +0 -0
  138. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_run_status.py +0 -0
  139. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_sdk_compat.py +0 -0
  140. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets.py +0 -0
  141. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets_integration.py +0 -0
  142. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets_pipeline.py +0 -0
  143. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_source_resolution.py +0 -0
  144. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_stages.py +0 -0
  145. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_step_workspace.py +0 -0
  146. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_sync_back.py +0 -0
  147. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_trigger_script.py +0 -0
  148. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit11.py +0 -0
  149. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit11_pbt.py +0 -0
  150. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_config.py +0 -0
  151. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_pbt.py +0 -0
  152. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_pure.py +0 -0
  153. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_verdict.py +0 -0
  154. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_viz_demo.py +0 -0
  155. {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_viz_layout.py +0 -0
@@ -0,0 +1,642 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentic-dev-loop
3
+ Version: 0.13.0
4
+ Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
5
+ Author: Luke Wilson
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/lukedawilson/agentic-dev-loop
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: MacOS
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Topic :: Security
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.12
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: pydantic>=2.0
29
+ Requires-Dist: PyYAML>=6.0
30
+ Requires-Dist: openhands-sdk~=1.17.0
31
+ Requires-Dist: openhands-tools~=1.17.0
32
+ Requires-Dist: agent-client-protocol<1.0.0
33
+ Requires-Dist: langgraph>=1.2
34
+ Requires-Dist: langgraph-checkpoint-sqlite>=3.0
35
+ Requires-Dist: msgpack>=1.0
36
+ Requires-Dist: filelock>=4.2.1
37
+ Requires-Dist: pyasn1>=0.6.5
38
+ Requires-Dist: pypdf>=6.21.4
39
+ Provides-Extra: dev
40
+ Requires-Dist: hypothesis>=6.0; extra == "dev"
41
+ Requires-Dist: pytest>=8.0; extra == "dev"
42
+ Requires-Dist: pip-audit>=2.0; extra == "dev"
43
+ Requires-Dist: pre-commit>=3.0; extra == "dev"
44
+ Dynamic: license-file
45
+
46
+ # agentic-dev-loop
47
+
48
+ > **Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.**
49
+
50
+ Describe your pipeline in one YAML file - agent steps, mechanical test gates, and
51
+ trusted actions - and `agentic-dev-loop` runs it end to end: agent and command steps get
52
+ kernel-level sandboxing via Docker, verdicts route the graph, every boundary is
53
+ checkpointed, and nothing gets committed until every gate passes.
54
+
55
+ ![The live graph view - pipeline graph with fail loopbacks, summary tiles, per-stage consoles, and event log](https://raw.githubusercontent.com/lukedawilson/agentic-dev-loop/main/docs/viz-pipeline.png)
56
+
57
+ - **A tool, not a wiring project.** One CLI entry point, opinionated defaults,
58
+ fixed safety policies. You write the pipeline and the agent definitions -
59
+ nothing else.
60
+ - **Deterministic.** Same pipeline + same state → same routing. Verdicts are
61
+ parsed from files, retries are bounded, nothing is best-effort.
62
+ - **Sandboxed by default.** The agent's shell and every command step run inside
63
+ an always-on Docker sandbox. There is no opt-out.
64
+
65
+ ## How it fits together
66
+
67
+ The loop is five layers. You author the first two; the engine owns the rest.
68
+
69
+ | Layer | What it is | Who authors it |
70
+ | --- | --- | --- |
71
+ | **Pipeline** | One `pipeline.yaml` declaring the stage graph: agent steps, mechanical command gates, verdict routing, retry loops, and per-step isolation. | You |
72
+ | **Agent prompts** | Markdown prompt files with YAML frontmatter (`<name>.agent.md`) defining each agent's role, rules, sandbox notes, and tools. | You |
73
+ | **Sandbox** | Every agent shell and command step runs in a Docker container: no network access by default, writes only to declared `mounts:`, and no `.git` - steps run against a fresh export. If no sandbox is available, the run stops instead of degrading. | Engine |
74
+ | **Dev image** | The digest-pinned dev image pulled on first run. The supply-chain check refuses to continue on a digest mismatch. | Engine |
75
+ | **Extensions** | Optional plugins: your own actions, tools, and document loaders, loaded from outside the workspace. | You (optional) |
76
+
77
+ Every run is crash-safe (interrupt and resume from the exact checkpoint),
78
+ watchable in a live browser graph view, and gated: nothing gets committed
79
+ until every stage passes. The fixed policies are part of the product - fail
80
+ fast on missing config or secrets, no silent fallbacks, verdicts only from
81
+ artifacts, bounded retries, and a single clean-worktree-gated commit point.
82
+
83
+ ## Supported platforms
84
+
85
+ The engine is plain Linux under the hood and runs wherever a compliant
86
+ Docker engine does:
87
+
88
+ | Platform | Support |
89
+ | --- | --- |
90
+ | **Linux** | Native. Docker Engine, OrbStack, Colima, or podman with docker compat. |
91
+ | **macOS** | Native. Docker Desktop, OrbStack, or Colima. |
92
+ | **Windows** | Via **WSL2** (Ubuntu distro). Enable Docker Desktop's WSL integration (or run Docker Engine inside the distro) and keep the repo on the WSL filesystem (`~/dev/...`), not `/mnt/c` - bind-mounting a 9p path into containers breaks permissions and is slow. |
93
+
94
+ ## Quick start
95
+
96
+ **Prerequisites**
97
+
98
+ | Requirement | Detail |
99
+ | --- | --- |
100
+ | Python | ≥ 3.12 |
101
+ | Docker engine | Engine API ≥ 1.43 (Engine 24). Any compliant engine works - Docker Desktop, OrbStack, Colima, Rancher Desktop, podman docker-compat. On Windows, run under WSL2: the repo must live on the WSL filesystem, not /mnt/c. |
102
+ | LLM API key | The env var named by your pipeline's `api_key_env` (e.g. `OPENAI_API_KEY`) must be set - a missing key fails fast, naming it. Alternatively, `agentic-dev-loop copilot-login` authenticates a Copilot subscription (see [LLM providers](#llm-providers)). |
103
+
104
+ ```bash
105
+ pipx install agentic-dev-loop
106
+ agentic-dev-loop --version
107
+ ```
108
+
109
+ Install with **pipx**: the engine's venv lives outside the workspace, so it
110
+ is unmounted from the sandbox and never agent-writable. On the first run the
111
+ engine pulls the digest-pinned dev image and verifies its digest. Setup
112
+ details and troubleshooting live in [docs/setup.md](docs/setup.md).
113
+
114
+ ```bash
115
+ cd <your-repo>
116
+ agentic-dev-loop init --profile python # writes the pipeline + agents (see below)
117
+ export OPENAI_API_KEY=... # whatever api_key_env names
118
+ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # validate - no LLM, no Docker
119
+ agentic-dev-loop agentic-dev-loop/pipeline.yaml # run it
120
+ ```
121
+
122
+ ## Running a pipeline
123
+
124
+ | Flag | Effect |
125
+ | --- | --- |
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
+ | `--resume <thread-id>` | Continue the latest checkpoint of a previous run (crash, Ctrl-C, exhaustion) with all accumulated notes intact. |
128
+ | `--max-attempts <n>` | Override the pipeline's `max_attempts`. |
129
+ | `--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
+ Exit code is `0` on pipeline success, `1` otherwise.
132
+
133
+ Other commands:
134
+
135
+ - `agentic-dev-loop run-status <pipeline>` renders the latest run as a
136
+ mermaid flowchart with the current step highlighted, reading the run-state
137
+ checkpoint database directly. `run-status --install` installs the bundled
138
+ `/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,
141
+ review, and QA metrics with provenance labels) or a deep dive for one
142
+ 12-hex run directory. `--since` / `--until` / `--status` filter the set.
143
+ Reporting is strictly read-only.
144
+ - `agentic-dev-loop containers` inspects the engine's sandbox containers and
145
+ networks from the host; `containers --reap` removes registry-owned orphans
146
+ whose owner process is dead. A SIGTERM to a running pipeline still closes
147
+ the sandbox; SIGKILLed runs are reclaimed by the startup reaper on the next
148
+ run or by `containers --reap`.
149
+
150
+ **What a run looks like** (the shipped self-loop example):
151
+
152
+ ```mermaid
153
+ flowchart LR
154
+ dev["agent: dev"] --> test{{"test gate"}} --> review["agent: review"] --> qa["agent: qa"] --> commit["action: commit"]
155
+ test -- fail --> dev
156
+ review -- fail --> dev
157
+ qa -- fail --> dev
158
+ ```
159
+
160
+ 1. **dev** - the dev agent works with full context (loaded docs + shared files).
161
+ Its edits are untracked; only declared `produces:` files are hygiene-tracked.
162
+ 2. **test** - a mechanical command step runs the suite inside the sandbox.
163
+ Exit 0 moves on; anything else rewinds to `dev` with the failing output.
164
+ 3. **review / qa** - verdict agents finish by calling the `record_verdict`
165
+ tool; the validated tool call routes the graph. `fail` rewinds to `dev`
166
+ and consumes an attempt.
167
+ 4. **commit** - the single commit point fires only when all gates passed and
168
+ the worktree was clean at start.
169
+ 5. **success** - committed; or **failure** when attempts are exhausted.
170
+
171
+ ## LLM providers
172
+
173
+ The engine speaks OpenAI-compatible wire format throughout, so every step,
174
+ profile, and gate works identically on either provider style:
175
+
176
+ | Provider | Setup |
177
+ | --- | --- |
178
+ | **Any OpenAI-compatible endpoint** | API key via `api_key_env` + `base_url` in the `llm:` block: DeepSeek, OpenAI, or any OpenAI-compatible API. |
179
+ | **GitHub Copilot subscription** | `agentic-dev-loop copilot-login` once, then point the `llm:` block at `https://api.githubcopilot.com` with the file-backed token. |
180
+
181
+ ```yaml
182
+ # OpenAI-compatible endpoint (any provider)
183
+ llm:
184
+ model: openai/deepseek-v4-pro
185
+ base_url: https://api.deepseek.com
186
+ api_key_env: OPENAI_API_KEY
187
+ ```
188
+
189
+ ```yaml
190
+ # GitHub Copilot subscription
191
+ llm:
192
+ model: openai/gpt-5.6-luna # pro tier; gpt-4.1 is the lite tier
193
+ base_url: https://api.githubcopilot.com
194
+ api_key_secret:
195
+ from: file
196
+ key: ~/.agentic-dev-loop/auth/copilot.json
197
+ json_key: access_token
198
+ headers:
199
+ Copilot-Integration-Id: vscode-chat
200
+ Editor-Version: vscode/1.94.0
201
+ Openai-Intent: conversation-panel
202
+ ```
203
+
204
+ Copilot specifics:
205
+
206
+ - The `openai/` prefix on model names is required - it forces the
207
+ OpenAI-compatible route through the gateway.
208
+ - `gpt-4.1` (lite tier) rejects any `reasoning_effort`, so lite-tier steps
209
+ set none.
210
+ - Some models on this endpoint do not work for agent steps. The current
211
+ working set, the token lifecycle, and known endpoint limitations are in
212
+ [docs/setup.md](docs/setup.md).
213
+
214
+ ## pipeline.yaml
215
+
216
+ ```yaml
217
+ name: my-construction-loop
218
+ extensions:
219
+ - agentic_dev_loop.engine.extensions.aidlc:AidlcExtension # bundled AI-DLC doc loader
220
+ additional_files:
221
+ - ../README.md # shared context for every agent step
222
+
223
+ llm:
224
+ model: openai/deepseek-v4-pro
225
+ base_url: https://api.deepseek.com
226
+ api_key_env: OPENAI_API_KEY
227
+ # reasoning_effort: medium # optional: low | medium | high | xhigh | none
228
+
229
+ # Named LLM profiles: a step names one with `llm: <name>` to move the whole
230
+ # profile (model, endpoint, key, effort default) together. The `llm:` block
231
+ # above remains the default.
232
+ # llms:
233
+ # review:
234
+ # model: openai/deepseek-v4-pro
235
+ # base_url: https://api.deepseek.com
236
+ # api_key_env: REVIEW_API_KEY
237
+ # reasoning_effort: xhigh
238
+
239
+ max_attempts: 10 # CLI --max-attempts overrides
240
+ agents_dir: sdk_agents # your <name>.agent.md files
241
+
242
+ steps:
243
+ - name: brief
244
+ reasoning_effort: medium
245
+ brief_inputs:
246
+ include: [AGENTS.md, coding-standards-ddd.yaml]
247
+ sections: [Repo rules digest, Unit scope digest, Environment facts, Open risks]
248
+ env_facts: ["the workspace is an export with no .git; verify with find/ls, never git status"]
249
+ on_pass: dev
250
+
251
+ - name: dev
252
+ agent: dev
253
+ produces: implementation-summary.md
254
+ terminal_timeout: 900
255
+ # forbidden_commands: ["npm install", "npm ci"] # per-step tool deny-list; engine defaults are git mutations + docker
256
+ on_pass: test
257
+
258
+ - name: test
259
+ command: .venv-sandbox/bin/python -m pytest tests/ -q -m "not docker"
260
+ setup: python -m venv .venv-sandbox && .venv-sandbox/bin/pip install -e ".[dev]"
261
+ timeout: 600
262
+ on_pass: review
263
+ on_fail: { goto: dev, retry: true }
264
+
265
+ - name: review
266
+ agent: review
267
+ artifact: review-findings.md
268
+ verdicts: { pass: APPROVED, fail: NEEDS CHANGES }
269
+ # reasoning_effort: xhigh # per-step override of the effective profile's effort
270
+ # llm: review # select a named `llms:` profile for this step
271
+ on_pass: qa
272
+ on_fail: { goto: dev, retry: true }
273
+
274
+ - name: qa
275
+ agent: qa
276
+ artifact: qa-report.md
277
+ verdicts: { pass: PASS, fail: FAIL }
278
+ max_iterations: 100
279
+ finalize_nudge_turns: 10
280
+ on_pass: commit
281
+ on_fail: { goto: dev, retry: true }
282
+
283
+ - name: commit
284
+ action: commit
285
+ params: { message: "feat: construct {subject} (agent dev loop)" }
286
+ ```
287
+
288
+ | Key | Notes |
289
+ | --- | --- |
290
+ | `agent:` / `command:` / `action:` / `brief_inputs:` | Exactly one per step. Agents live in `agents_dir` as `<name>.agent.md`; commands run sandboxed (mechanical, never an LLM call). `commit` is the sole host-side built-in action; consumer actions are sandbox-executed scripts (see [Host boundary](#host-boundary-security-model)). |
291
+ | `produces:` / `artifact:` + `verdicts:` | Hygiene-tracked outputs vs structured-verdict routing. The verdict comes from a validated `record_verdict` tool call, never from prose; stale artifacts are deleted at each attempt start. |
292
+ | `brief_inputs:` | A native brief step: `{ include: [<paths/globs>], env_facts: [<strings>], sections: [<headings>] }`. It digests the included docs into an engine-owned `attempt-brief.md` that later agents read, and re-runs only when its inputs change. |
293
+ | `on_pass:` / `on_fail:` | A step name, terminal `success`/`failure`, or `{goto: X, retry: true}`. No loops happen unless you write them. |
294
+ | `env:` / `setup:` / `network:` | `env:` declares step vars (fixed safe base + declared vars only); `setup:` runs fresh at every step boundary in a one-shot provision container targeting the export (command or agent steps; network ON); `network: true` grants egress scoped by `egress:` (default off) - see [Per-stage networking](#per-stage-networking). |
295
+ | `mounts:` / `egress:` | Per-step workspace isolation. `mounts:` lists `{path, mode}` entries (`rw`/`ro`, default `ro`), strict-by-default: empty/missing mounts nothing, and only declared-rw paths sync back to the repo. `egress:` names the hosts a networked step may reach (`{class, presets, targets}`). See [docs/setup.md](docs/setup.md). |
296
+ | `secrets:` (top-level) / step `secrets:` | Declares secret **refs only - never values**; each step opts in to the refs it needs. Resolved host-side and injected into that step's exec env only. See [Secrets](#secrets). |
297
+ | `profile:` (top-level) | Names a bundled toolchain profile (`python`, `dotnet-node`) or a consumer profile file path, merged at load time: isolation key-wise with the pipeline winning, caches unioned profile-first. |
298
+ | `isolation:` (optional) | Configures the sandbox - image override, resource caps, `allow_git_mutations`, `seccomp_profile`. It can never disable it. See [browser sandbox](docs/browser-sandbox.md). |
299
+ | `terminal_timeout:` | Optional agent-step per-action timeout in seconds; overrides the SDK tool default. |
300
+ | `finalize_nudge_turns:` | Optional agent-step final-response nudge; requires `max_iterations:` and must be less than it. |
301
+ | `deps_policy:` / `lockfiles:` | `locked` (default) or `open`. The human-owned lockfile is the source of truth under `locked`; see [Dependency policy](#dependency-policy-locked-by-default). |
302
+ | `caches:` / `sync_excludes:` | Top-level run-wide lists. `caches:` names toolchain cache dirs bind-mounted rw from host-side stores (a `setup:` hook can warm them); `sync_excludes:` names non-gitignored scratch paths skipped from export and sync-back. |
303
+ | `merge_on_conflict:` | Top-level list of append-style logs. A concurrent host edit to a listed path is union-merged instead of raising; see [Sync-back conflicts](#sync-back-conflicts-host-edits-during-a-run). |
304
+ | `llms:` (top-level) / step `llm:` / `reasoning_effort:` | Named LLM profiles, each a full `LlmConfig`; a step selects one whole with `llm: <name>`. `reasoning_effort` (`low`/`medium`/`high`/`xhigh`/`none`) is opt-in on the `llm` block, a profile, or a step. See [Reasoning effort](#reasoning-effort-opt-in). |
305
+
306
+ ### Banned commands (`forbidden_commands:`)
307
+
308
+ `forbidden_commands:` is a per-step list of regex patterns checked against
309
+ every agent command before any shell spawn; a match returns a structured
310
+ `[forbidden: <label>]` observation instead of running. The engine defaults
311
+ (git mutations and docker) always apply and have no disable switch; a
312
+ toolchain profile may add tool-specific rules (for example the `python`
313
+ recipe denies `pip install`, `uv add`, and `pip-compile` on agent steps).
314
+ Command steps bypass the filter by design.
315
+
316
+ ### Reasoning effort (opt-in)
317
+
318
+ `reasoning_effort` is an opt-in latency dial on the pipeline `llm` block, a
319
+ named `llms:` profile, and individual agent steps. Unset means reasoning is
320
+ off - the field is forwarded as none and reasoning is stripped from requests.
321
+ A thinking model without an effort level is invalid config and fails fast
322
+ with an actionable engine error rather than a provider 400. A step's value
323
+ overrides the effective profile's value.
324
+
325
+ Recommended lane defaults (guidance only, not enforced):
326
+
327
+ | Lane | reasoning_effort | Why |
328
+ | --- | --- | --- |
329
+ | brief | medium | digest and classify, no design work |
330
+ | dev | high | the most demanding construction work |
331
+ | qa | medium | classification discipline must stay reliable |
332
+ | review | xhigh | highest stakes: a missed detection sails past the last gate into commit |
333
+
334
+ ### Secrets
335
+
336
+ Secret values never belong in the pipeline yaml, the workspace, or `state_dir`.
337
+ Declare the refs at the top level and opt each step into the refs it needs:
338
+
339
+ ```yaml
340
+ secrets: # refs only - never values
341
+ kinde-client-secret: # ref name (arbitrary)
342
+ from: env # provider name
343
+ key: KINDIE_CLIENT_SECRET # provider-specific locator
344
+ r2-keys:
345
+ from: env
346
+ key: R2_KEYS
347
+
348
+ steps:
349
+ - name: qa
350
+ agent: qa
351
+ secrets: [kinde-client-secret, r2-keys]
352
+ ```
353
+
354
+ - The engine resolves every declared ref host-side at run start; a missing
355
+ variable, unknown provider, or undeclared ref fails fast, naming the ref.
356
+ A resolved secret reaches only the steps that list it.
357
+ - Prefer a mechanical `command` step for secret-consuming work so the LLM and
358
+ the secret never meet; an `agent` step holds a secret only when its job
359
+ genuinely requires it.
360
+ - **`.env*` ban.** At run start the workspace root is scanned for `.env*`
361
+ files; any hit fails fast, naming the files. The convention fixtures
362
+ `.env.example`, `.env.template`, and `.env.sample` are whitelisted.
363
+ - **Output scrubbing.** Resolved secret values are scrubbed from every
364
+ engine-written output - captured step output, retry notes, artifacts, and
365
+ `state_dir` files.
366
+ - `from: file` reads a host file (`key` is the path, optional `json_key`
367
+ selects a JSON field); the `llm:` block accepts exactly one of `api_key_env`
368
+ or `api_key_secret`. See [docs/setup.md](docs/setup.md).
369
+
370
+ ### Per-stage networking
371
+
372
+ The sandbox is network-off by default. A step that legitimately needs egress
373
+ declares `network: true` and names exactly what it may reach:
374
+
375
+ ```yaml
376
+ steps:
377
+ - name: fetch-docs
378
+ command: curl -fsSL https://example.com/spec.json -o spec.json
379
+ mounts: [{ path: ".", mode: rw }] # the cwd + a place to write spec.json
380
+ network: true # egress for this step only
381
+ egress: { targets: [example.com] } # ...and only these hosts
382
+
383
+ - name: restore
384
+ command: .venv-sandbox/bin/pip install -e ".[dev]"
385
+ mounts: [{ path: ".", mode: rw }]
386
+ network: true
387
+ egress: { presets: [package-registries] } # pypi/npm/NuGet/cargo + VCS
388
+ ```
389
+
390
+ - `network: true` is scoped by the `egress:` allowlist, structurally: the
391
+ step's traffic is forced through a containerized egress proxy on a per-run
392
+ internal docker network with no route to the host, and a request to an
393
+ undeclared host is denied and logged. `egress: { class: browser }` is the
394
+ explicit broad-but-logged class (every connection logged, nothing
395
+ filtered); otherwise the allowlist is strict.
396
+ - A networked step that writes output must also declare a writable mount:
397
+ with no `mounts:` a step mounts nothing, so `curl ... -o spec.json` has no
398
+ writable cwd.
399
+ - Host services are reachable through the proxy's `host.docker.internal`
400
+ host-gateway alias, so an S3 SDK against a local MinIO works through the
401
+ enforced, logged path. Sandbox containers have no host route.
402
+ - Command, agent, and sandbox-action steps may declare it; the host-side
403
+ `commit` action never takes it. Author opt-in is the control - reserve it
404
+ for stages that need it (QA, integration).
405
+
406
+ ### Sync-back conflicts (host edits during a run)
407
+
408
+ Only declared-`rw` paths sync back to the real repo after a step. If the host
409
+ also edits a declared-`rw` path while the step is running, sync-back raises
410
+ `AE-SBX-016`; the host's version wins, the baseline is re-snapshotted, and the
411
+ next step runs clean instead of re-raising forever. For append-style logs
412
+ edited by both sides, declare them in the top-level `merge_on_conflict:`
413
+ list: they are union-merged - the host keeps its lines, the sandbox's new
414
+ lines are appended, and the run continues.
415
+
416
+ ### Dependency policy (locked by default)
417
+
418
+ The supply-chain dial is a pipeline-level `deps_policy:` field, **locked by
419
+ default**. The engine injects the policy into every agent step's context:
420
+
421
+ ```yaml
422
+ deps_policy: locked # or: open (default: locked)
423
+ lockfiles: [uv.lock] # or: [packages.lock.json, package-lock.json]
424
+ ```
425
+
426
+ - **`locked`** - the human-owned lockfile is the source of truth; the agent
427
+ may not add dependencies. If the design requires a missing dependency, the
428
+ agent declares it in its final response under `## Missing dependencies`,
429
+ which fails the run fast with one human lockfile edit - not a retry loop.
430
+ - **`open`** - the agent may add exact-pinned manifest entries directly
431
+ (never a package-manager `add` command); the network-on restore step
432
+ fetches them.
433
+
434
+ The **restore step** runs the toolchain's locked mode and fails when the
435
+ manifest and lockfile disagree:
436
+
437
+ | Toolchain | Locked restore | Lockfile |
438
+ | --- | --- | --- |
439
+ | .NET | `dotnet restore --locked-mode` | `packages.lock.json` |
440
+ | node | `npm ci` | `package-lock.json` |
441
+ | python | `uv sync --locked` | `uv.lock` |
442
+
443
+ The restore step also fails on known-CVE findings (per-toolchain thresholds:
444
+ NuGetAudit at `error`, `npm audit --audit-level=high`, `pip-audit`). A human
445
+ generates the lockfile once, on a network machine, and commits it - the
446
+ engine never fetches on the agent's behalf.
447
+
448
+ ### Host boundary (security model)
449
+
450
+ The orchestrator, tool layer, and the `commit` action run in the host process
451
+ - they hold your credentials and your full user account, so the engine keeps
452
+ anything agent-writable out of that process:
453
+
454
+ - **Consumer actions are sandbox-executed.** An action you register via an
455
+ extension is a command-shaped script (`script + params`), run through the
456
+ same sandbox path as command steps. Only the engine's trusted built-ins
457
+ (`commit`, document loaders) run host-side.
458
+ - **Extensions load from outside the workspace.** Any extension or tool
459
+ module whose file resolves under the workspace is refused before import,
460
+ naming the file.
461
+ - **The engine installs outside the workspace.** Install with pipx so the
462
+ venv is unmounted from the sandbox; a startup self-check refuses to run if
463
+ `agentic_dev_loop` resolves under the workspace.
464
+ - **Tooling is read-only by the loop.** At run start the pipeline file,
465
+ `agents_dir`, `additional_files`, `aidlc-docs/`, and `tools/` must be
466
+ git-clean relative to HEAD, and the `commit` action excludes those paths
467
+ from its sweep, so the loop never commits its own tooling.
468
+ - **`commit` stays host-side, deliberately.** It holds push credentials and
469
+ runs argv-style with a scrubbed child env and a hooks override, so repo
470
+ hooks never execute.
471
+
472
+ Net: the host executes nothing from the workspace, reads only git-clean
473
+ control files, and the only agent-writable host-consumed thing left is the
474
+ code the loop is building.
475
+
476
+ ## Authoring a loop for your own repo
477
+
478
+ ### Start with `agentic-dev-loop init`
479
+
480
+ ```bash
481
+ agentic-dev-loop init --profile python # or: --profile dotnet-node
482
+ ```
483
+
484
+ `init` writes the onboarding surface from a bundled toolchain profile:
485
+ `agentic-dev-loop/pipeline.yaml`, the three agent files, an executable
486
+ `trigger-agentic-dev-loop.sh`, `agentic-dev-loop/.engine-version` (the exact
487
+ installed engine version), any missing premise files, gitignore additions,
488
+ and an env-file template. It detects solution files, `package.json`
489
+ directories, lockfiles, README, and AGENTS.md, asks only what detection
490
+ cannot answer, and refuses to overwrite an existing `agentic-dev-loop/`
491
+ directory. A consumer-authored profile file can be passed by path instead of
492
+ a bundled name.
493
+
494
+ `agentic-dev-loop doctor --fast` is the per-run gate the trigger runs first:
495
+ hard failures abort the run (engine pin mismatch, engine runtime
496
+ availability, API version, git repo, `.env*` files); warnings print and
497
+ continue. On a hard failure the trigger runs `agentic-dev-loop upgrade`
498
+ exactly once, then the run fails hard if doctor still fails.
499
+
500
+ A consumer repo needs a pipeline file and the agent files it names, both
501
+ committed before the first run. `init` writes them; the layout is:
502
+
503
+ ```
504
+ <repo>/agentic-dev-loop/pipeline.yaml
505
+ <repo>/agentic-dev-loop/sdk_agents/dev.agent.md
506
+ <repo>/agentic-dev-loop/sdk_agents/review.agent.md
507
+ <repo>/agentic-dev-loop/sdk_agents/qa.agent.md
508
+ ```
509
+
510
+ ### The agent files
511
+
512
+ Each `sdk_agents/<name>.agent.md` is a markdown prompt plus YAML frontmatter:
513
+ `name` matches a step's `agent:` value; `tools` lists the tool names the step
514
+ may use (`terminal` always; verdict steps also need `record_verdict`; a repo
515
+ can add more via extensions). A step configured with `verdicts:` whose agent
516
+ file does not grant `record_verdict` fails at load, never at routing time.
517
+
518
+ ```markdown
519
+ ---
520
+ name: review # matches a step's `agent:` value
521
+ tools: [terminal, record_verdict]
522
+ ---
523
+ # Review Agent
524
+ ## WORKFLOW # numbered steps
525
+ ## RULES # absolute never/always rules
526
+ ## SANDBOX NOTES # the sandbox truth for THIS step
527
+ ## OUTPUT # the verdict contract
528
+ ```
529
+
530
+ Three roles, three contracts:
531
+
532
+ | Role | Verdict contract | Typical sandbox |
533
+ | --- | --- | --- |
534
+ | dev | none - the final response is captured as the `produces:` summary | rw mount, offline |
535
+ | review | `record_verdict` with `APPROVED` / `NEEDS CHANGES`; the prose keeps the findings for humans | ro mount, offline |
536
+ | qa | `record_verdict` with `PASS` / `FAIL`; map `unverifiable: UNVERIFIABLE` if you want a third way | shaped by the repo: rw + network + `class: browser` when it boots servers and drives a browser; ro + offline when it probes the CLI only |
537
+
538
+ Conventions that make a good agent file:
539
+
540
+ - **State the sandbox truth in the prompt.** Every agent file carries a
541
+ `SANDBOX NOTES` section naming exactly what its step allows: mounts ro or
542
+ rw, network on or off, and which gates have already run.
543
+ - **Gates are the source of truth - cite the record, never re-run.** Review
544
+ and qa never re-run builds or suites; qa maps every acceptance criterion to
545
+ existing coverage and probes only the remainder.
546
+ - **dev enumerates its impossible set and stops at it.** List the commands
547
+ the sandbox cannot run (offline package fetches, browser downloads), one
548
+ attempt per command - keeps the productive loop and kills doomed retries.
549
+ - **Failure output returns as *Previous attempt feedback*.** Steps route
550
+ `on_fail: { goto: dev, retry: true }`, so gate failure output lands in the
551
+ dev agent's next context; the dev prompt makes every listed issue a
552
+ required fix.
553
+ - **No git mutations, ever.** The `commit` step is the single commit point.
554
+
555
+ ### The pipeline file
556
+
557
+ The full field reference is above; this is the stage lineup and what to
558
+ adapt per repo.
559
+
560
+ | Stage | Kind | Typical shape | Why |
561
+ | --- | --- | --- | --- |
562
+ | dev | agent | rw, offline | does the work; edits are untracked |
563
+ | restore | command | network + `presets: [package-registries]` | fetches what dev pinned (`deps_policy: open`) or the locked install |
564
+ | test | command | offline is fine (warm cache) | exit code is the verdict; the source of truth |
565
+ | editor-tests | command | network + `presets: [package-registries]` | frontend suites that cannot run offline; a separate step keeps its failure diagnosis and timeout independent of the backend suite |
566
+ | conformance | command | network + `presets: [package-registries]` | repo-specific fitness checks |
567
+ | review | agent | ro, offline | static conformance verdict |
568
+ | qa | agent | per repo (see table above) | live-behaviour probes; inject secrets only if the probes need them |
569
+ | commit | action | host-side | the single commit point |
570
+
571
+ Adaptation checklist for a new repo:
572
+
573
+ 1. `llm:` - model, `base_url`, `api_key_env`.
574
+ 2. `llms:` (optional) - named profiles for multi-provider lanes (keep review
575
+ on the strongest model); a step opts in with `llm: <name>`.
576
+ 3. `profile:` - name a bundled profile (`python`, `dotnet-node`) or a
577
+ consumer profile path.
578
+ 4. `caches:` - profile-supplied toolchain caches plus any run-specific dirs;
579
+ caches are never synced back, and a step's `setup:` hook runs with them
580
+ mounted so it can warm them.
581
+ 5. `sync_excludes:` - build output trees (`**/bin/**`, `**/obj/**`).
582
+ 6. `secrets:` - refs only, resolved from host env; each step opts in to the
583
+ refs it needs.
584
+ 7. `egress:` - `presets: [package-registries]` for fetch steps;
585
+ `class: browser` (broad-but-logged) for browser-tier qa only.
586
+ 8. `deps_policy:` and `lockfiles:` - see
587
+ [Dependency policy](#dependency-policy-locked-by-default).
588
+ 9. The dev prompt's impossible set - write it for your toolchain.
589
+ 10. `additional_files:` - the repo's `AGENTS.md`, coding standards, design
590
+ docs: shared context for every agent step.
591
+
592
+ Validate before the first run - dry-run loads and prints the resolved plan
593
+ with no LLM, no Docker, no state writes:
594
+
595
+ ```bash
596
+ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run
597
+ ```
598
+
599
+ Then commit the tooling and run for real.
600
+
601
+ ## Development environment
602
+
603
+ ```bash
604
+ git clone git@github.com:lukedawilson/agentic-dev-loop.git
605
+ cd agentic-dev-loop
606
+ pipx install agentic-dev-loop # engine venv OUTSIDE the workspace (self-check)
607
+ export OPENAI_API_KEY=... # set your LLM key in the host env (no .env in the repo)
608
+ python -m pytest tests/ -q # fast suite (in-repo .venv is for tests only)
609
+ python -m pytest tests/ -q -m "not docker" # skip engine-dependent tests
610
+ agentic-dev-loop agentic-dev-loop/pipeline.yaml --dry-run # run the shipped pipeline
611
+ ./run-demo.sh # viz demo - scripted run replay, no pipeline needed
612
+ ```
613
+
614
+ - `setup-venv.sh` builds the throwaway `.venv` for local `pytest` runs. The
615
+ loop itself must run from the pipx install - never an in-workspace `.venv`,
616
+ which the startup self-check refuses.
617
+ - Docker-marked integration tests need a local daemon; CI runs them on Linux.
618
+ - The shipped pipeline (`agentic-dev-loop/pipeline.yaml`) dogfoods the tool
619
+ on its own repo - dev → test → review → qa → commit, with the engine's own
620
+ three agent definitions in `sdk_agents/`.
621
+ - CI: `ci.yml` (unit + integration suite, ubuntu), `publish-image.yml`
622
+ (multi-arch dev image, amd64 + arm64), `release.yml` (PyPI publishing).
623
+ - Pre-publish tooling can point `AGENTIC_DEV_LOOP_DEV_IMAGE` at a locally
624
+ built dev image.
625
+
626
+ ## Contributing
627
+
628
+ - **Read [AGENTS.md](AGENTS.md) first** - it is the instruction set for both
629
+ human and agent contributors.
630
+ - Development is structured by **AI-DLC** - the lifecycle workflow in
631
+ `.aidlc/aidlc-rules/aws-aidlc-rules/` with working docs in `aidlc-docs/`.
632
+ The bundled document loader autodetects the current unit via
633
+ `--aidlc-unit`, or loads any plan with `--plan`.
634
+ - OpenCode commands over the workflow: `/unit-status`, `/epic-status`,
635
+ `/ticket-details`, `/update-subtask`, `/apply-aidlc-patches`, and more.
636
+ - Working extension samples (actions, tools, document loaders) ship as
637
+ `tests/sample_ext.py`.
638
+
639
+ ---
640
+
641
+ Built on [OpenHands SDK](https://github.com/OpenHands/software-agent-sdk) and
642
+ [LangGraph](https://github.com/langchain-ai/langgraph).