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.
- agentic_dev_loop-0.13.0/PKG-INFO +642 -0
- agentic_dev_loop-0.13.0/README.md +597 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/pyproject.toml +1 -1
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/cli.py +67 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/graph.py +2 -1
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/provider_wire.py +7 -0
- agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/__init__.py +43 -0
- agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/metrics.py +593 -0
- agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/render.py +175 -0
- agentic_dev_loop-0.13.0/src/agentic_dev_loop/reporting/sources.py +770 -0
- agentic_dev_loop-0.13.0/src/agentic_dev_loop/viz/page.py +9 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/server.py +7 -3
- agentic_dev_loop-0.13.0/src/agentic_dev_loop.egg-info/PKG-INFO +642 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/SOURCES.txt +5 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_cli.py +3 -1
- agentic_dev_loop-0.13.0/tests/test_unit12_reporting.py +309 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_viz.py +27 -2
- agentic_dev_loop-0.12.2/PKG-INFO +0 -936
- agentic_dev_loop-0.12.2/README.md +0 -891
- agentic_dev_loop-0.12.2/src/agentic_dev_loop/viz/page.py +0 -9
- agentic_dev_loop-0.12.2/src/agentic_dev_loop.egg-info/PKG-INFO +0 -936
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/LICENSE +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/setup.cfg +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/config.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/failure.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/paths.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/data/dotnet-node.yaml +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/profiles/data/python.yaml +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/results.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/core/verdict.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/actions.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agent_error_guide.md +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agent_error_guide.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/agents.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/allowlist.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_coverage.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_prompt.md +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/brief_prompt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/completion.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/containers.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/copilot_auth.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/deps.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/dryrun.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/egress_proxy.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/forbidden.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/isolation.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/llm.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/loaders.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/mounts.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/checks.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/doctor.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/init.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes/dotnet-node.yaml +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes/python.yaml +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/recipes.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/dev.agent.md +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/env.example +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/qa.agent.md +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates/review.agent.md +0 -0
- {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
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/templates.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/onboarding/upgrade.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/outputs.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/presets.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/proc.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/registry.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/run_status.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/run_status_command.md +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/secrets.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/stages.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/engine/sync_back.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/py.typed +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/__init__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/__main__.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop/viz/layout.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_029_merge_on_conflict.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_033_brief_step.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_035_finalize_nudge.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_036_banned_commands_and_lane_boundary.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_041_brief_coverage.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_046_brief_prompt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_cli.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_doctor.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_init.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_profile_loading.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_profiles.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_recipes.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_schema_lock.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_templates.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_055_upgrade.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_actions.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_agent_error_guide.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_agents.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_aidlc.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_build_viz_page.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_config.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_containers.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_copilot_auth.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_copilot_cli.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_deps.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_dry_run.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_e2e_fixtures.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_egress_proxy.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_graph.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_hostboundary.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_hostboundary_integration.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation_integration.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_isolation_pbt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_llm.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_loaders.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_module_contract.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_outputs.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_outputs_pbt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_proc.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_provider_wire.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_publish.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_qa_prompt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_registry.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_repo_ascii.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_results.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_run_status.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_sdk_compat.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets_integration.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_secrets_pipeline.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_source_resolution.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_stages.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_step_workspace.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_sync_back.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_trigger_script.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit11.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit11_pbt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_config.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_pbt.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_unit5_pure.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_verdict.py +0 -0
- {agentic_dev_loop-0.12.2 → agentic_dev_loop-0.13.0}/tests/test_viz_demo.py +0 -0
- {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
|
+

|
|
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).
|