agentpack-cli 0.3.22__tar.gz → 0.3.23__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 (154) hide show
  1. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/PKG-INFO +10 -9
  2. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/README.md +9 -8
  3. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/pyproject.toml +1 -1
  4. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/__init__.py +1 -1
  5. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/ci_cmd.py +10 -0
  6. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/workflow_cmd.py +215 -8
  7. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/config.py +5 -0
  8. agentpack_cli-0.3.23/src/agentpack/core/loop_protocol.py +873 -0
  9. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/collectors.py +23 -0
  10. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/models.py +11 -0
  11. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/renderers.py +8 -2
  12. agentpack_cli-0.3.22/src/agentpack/core/loop_protocol.py +0 -349
  13. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/.gitignore +0 -0
  14. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/LICENSE +0 -0
  15. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/__init__.py +0 -0
  16. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/antigravity.py +0 -0
  17. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/base.py +0 -0
  18. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/claude.py +0 -0
  19. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/codex.py +0 -0
  20. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/cursor.py +0 -0
  21. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/detect.py +0 -0
  22. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/generic.py +0 -0
  23. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/adapters/windsurf.py +0 -0
  24. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/__init__.py +0 -0
  25. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/dependency_graph.py +0 -0
  26. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/go_imports.py +0 -0
  27. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/java_imports.py +0 -0
  28. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/js_ts_imports.py +0 -0
  29. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/monorepo.py +0 -0
  30. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/naming_signals.py +0 -0
  31. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/python_ast.py +0 -0
  32. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/python_imports.py +0 -0
  33. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/ranking.py +0 -0
  34. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/repo_map.py +0 -0
  35. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/role_inference.py +0 -0
  36. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/rust_imports.py +0 -0
  37. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/symbols.py +0 -0
  38. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/task_classifier.py +0 -0
  39. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/analysis/tests.py +0 -0
  40. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/application/__init__.py +0 -0
  41. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/application/pack_service.py +0 -0
  42. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/cli.py +0 -0
  43. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/__init__.py +0 -0
  44. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/_shared.py +0 -0
  45. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/benchmark.py +0 -0
  46. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/claude_cmd.py +0 -0
  47. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/compress_output.py +0 -0
  48. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/dashboard.py +0 -0
  49. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/dev_check.py +0 -0
  50. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/diagnose_selection.py +0 -0
  51. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/diff.py +0 -0
  52. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/doctor.py +0 -0
  53. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/eval_cmd.py +0 -0
  54. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/explain.py +0 -0
  55. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/guard.py +0 -0
  56. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/hook_cmd.py +0 -0
  57. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/ignore_cmd.py +0 -0
  58. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/init.py +0 -0
  59. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/install.py +0 -0
  60. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/learn.py +0 -0
  61. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/mcp_cmd.py +0 -0
  62. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/memory.py +0 -0
  63. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/migrate.py +0 -0
  64. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/monitor.py +0 -0
  65. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/next_cmd.py +0 -0
  66. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/pack.py +0 -0
  67. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/perf.py +0 -0
  68. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/quickstart.py +0 -0
  69. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/release_check.py +0 -0
  70. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/release_cmd.py +0 -0
  71. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/repair.py +0 -0
  72. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/retrieve.py +0 -0
  73. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/route.py +0 -0
  74. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/scan.py +0 -0
  75. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/skills.py +0 -0
  76. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/start_cmd.py +0 -0
  77. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/state_cmd.py +0 -0
  78. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/stats.py +0 -0
  79. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/status.py +0 -0
  80. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/summarize.py +0 -0
  81. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/task_cmd.py +0 -0
  82. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/threads.py +0 -0
  83. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/tune.py +0 -0
  84. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/verify_wheel.py +0 -0
  85. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/watch.py +0 -0
  86. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/commands/wrap.py +0 -0
  87. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/__init__.py +0 -0
  88. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/bootstrap.py +0 -0
  89. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/cache.py +0 -0
  90. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/changed_paths.py +0 -0
  91. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/context_pack.py +0 -0
  92. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/diff.py +0 -0
  93. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/evals.py +0 -0
  94. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/execution_state.py +0 -0
  95. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/git.py +0 -0
  96. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/git_hooks.py +0 -0
  97. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/global_install.py +0 -0
  98. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/ignore.py +0 -0
  99. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/merkle.py +0 -0
  100. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/models.py +0 -0
  101. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/modes.py +0 -0
  102. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/pack_registry.py +0 -0
  103. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/redactor.py +0 -0
  104. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/scanner.py +0 -0
  105. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/snapshot.py +0 -0
  106. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/task_freshness.py +0 -0
  107. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/thread_context.py +0 -0
  108. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/token_estimator.py +0 -0
  109. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/core/vscode_tasks.py +0 -0
  110. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/dashboard/__init__.py +0 -0
  111. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/data/agentpack.md +0 -0
  112. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/__init__.py +0 -0
  113. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/antigravity.py +0 -0
  114. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/claude.py +0 -0
  115. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/codex.py +0 -0
  116. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/cursor.py +0 -0
  117. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/installers/windsurf.py +0 -0
  118. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/__init__.py +0 -0
  119. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/agents.py +0 -0
  120. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/git_hooks.py +0 -0
  121. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/global_install.py +0 -0
  122. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/platform.py +0 -0
  123. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/integrations/vscode_tasks.py +0 -0
  124. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/__init__.py +0 -0
  125. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/collector.py +0 -0
  126. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/extractor.py +0 -0
  127. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/feedback.py +0 -0
  128. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/lesson_ranker.py +0 -0
  129. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/models.py +0 -0
  130. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/provider.py +0 -0
  131. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/quality.py +0 -0
  132. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/renderers.py +0 -0
  133. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/learning/skill_map.py +0 -0
  134. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/mcp_server.py +0 -0
  135. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/output_compression/__init__.py +0 -0
  136. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/output_compression/core.py +0 -0
  137. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/__init__.py +0 -0
  138. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/compact.py +0 -0
  139. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/markdown.py +0 -0
  140. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/renderers/receipts.py +0 -0
  141. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/__init__.py +0 -0
  142. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/discovery.py +0 -0
  143. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/models.py +0 -0
  144. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/parser.py +0 -0
  145. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/prompt_builder.py +0 -0
  146. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/scoring.py +0 -0
  147. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/service.py +0 -0
  148. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/router/skills_index.py +0 -0
  149. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/__init__.py +0 -0
  150. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/events.py +0 -0
  151. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/session/state.py +0 -0
  152. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/__init__.py +0 -0
  153. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/base.py +0 -0
  154. {agentpack_cli-0.3.22 → agentpack_cli-0.3.23}/src/agentpack/summaries/offline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentpack-cli
3
- Version: 0.3.22
3
+ Version: 0.3.23
4
4
  Summary: Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows.
5
5
  Project-URL: Homepage, https://github.com/vishal2612200/agentpack
6
6
  Project-URL: Documentation, https://vishal2612200.github.io/agentpack/
@@ -77,19 +77,20 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
77
77
 
78
78
  ![AgentPack route demo](docs/assets/agentpack-route-demo.svg)
79
79
 
80
- > **Status: alpha (v0.3.22).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
80
+ > **Status: alpha (v0.3.23).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
81
81
  >
82
82
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
83
83
  >
84
84
  > **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
85
85
 
86
- ## What's New in 0.3.22
86
+ ## What's New in 0.3.23
87
87
 
88
- `0.3.22` is a benchmark recall release. It promotes maintenance-context
89
- recovery to the current expanded public-suite baseline: **66.0% recall / 51.1%
90
- token precision** across 108 scored public cases.
91
- `0.3.21` established the prior honest baseline at **57.0% recall / 50.6% token precision**. The new result clears the 65% recall target while keeping token
92
- precision above the 51% release floor; remaining risk is config/build recall and NestJS token precision. Result: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md).
88
+ `0.3.23` is a guarded-loop hardening release. It keeps AgentPack's core promise
89
+ focused on local context and workflow evidence while making `agentpack work --run`
90
+ an optional proof harness around existing agents. The loop now has known runner
91
+ adapters, smoke checks, phase/diff/risk/acceptance artifacts, rollback patches,
92
+ metrics, and stricter finish gates. The prior expanded public-suite baseline
93
+ remains **66.0% recall / 51.1% token precision** across 108 scored public cases.
93
94
 
94
95
  ## Core Workflow
95
96
 
@@ -245,7 +246,7 @@ agentpack status
245
246
  agentpack finish --since main
246
247
  ```
247
248
 
248
- Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path.
249
+ Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path. Optional guardrail: `agentpack work --run` is a proof harness around existing agents, not AgentPack's default workflow or an autonomous coding agent.
249
250
 
250
251
  ### Learn from AI-assisted work
251
252
 
@@ -30,19 +30,20 @@ pipx run --spec agentpack-cli agentpack route --task "fix auth token expiry"
30
30
 
31
31
  ![AgentPack route demo](docs/assets/agentpack-route-demo.svg)
32
32
 
33
- > **Status: alpha (v0.3.22).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
33
+ > **Status: alpha (v0.3.23).** Works, tested, and used in real sessions. Python and JavaScript/TypeScript are the best-supported languages. Current benchmarks are useful regression checks, not broad proof that AgentPack improves coding-agent success. API may change before 1.0.
34
34
  >
35
35
  > **Platform note:** macOS, Linux, and Windows are supported. Windows support targets PowerShell plus Git for Windows. `cmd.exe` and bare Git setups are not a supported path yet.
36
36
  >
37
37
  > **Name note:** PyPI package is `agentpack-cli`, npm package is `@vishal2612200/agentpack`, and the command is `agentpack`. This project is unrelated to AgentPack dataset papers or other repos with the same name.
38
38
 
39
- ## What's New in 0.3.22
39
+ ## What's New in 0.3.23
40
40
 
41
- `0.3.22` is a benchmark recall release. It promotes maintenance-context
42
- recovery to the current expanded public-suite baseline: **66.0% recall / 51.1%
43
- token precision** across 108 scored public cases.
44
- `0.3.21` established the prior honest baseline at **57.0% recall / 50.6% token precision**. The new result clears the 65% recall target while keeping token
45
- precision above the 51% release floor; remaining risk is config/build recall and NestJS token precision. Result: [`benchmarks/results/2026-06-13-public.md`](benchmarks/results/2026-06-13-public.md).
41
+ `0.3.23` is a guarded-loop hardening release. It keeps AgentPack's core promise
42
+ focused on local context and workflow evidence while making `agentpack work --run`
43
+ an optional proof harness around existing agents. The loop now has known runner
44
+ adapters, smoke checks, phase/diff/risk/acceptance artifacts, rollback patches,
45
+ metrics, and stricter finish gates. The prior expanded public-suite baseline
46
+ remains **66.0% recall / 51.1% token precision** across 108 scored public cases.
46
47
 
47
48
  ## Core Workflow
48
49
 
@@ -198,7 +199,7 @@ agentpack status
198
199
  agentpack finish --since main
199
200
  ```
200
201
 
201
- Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path.
202
+ Use `agentpack quickstart --task "..." --write` when you want AgentPack to print the next commands and write the task file for you. Use `agentpack start "..." --pack-only` when you want only a fresh pack and not the guard path. Optional guardrail: `agentpack work --run` is a proof harness around existing agents, not AgentPack's default workflow or an autonomous coding agent.
202
203
 
203
204
  ### Learn from AI-assisted work
204
205
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentpack-cli"
3
- version = "0.3.22"
3
+ version = "0.3.23"
4
4
  description = "Local context engine for AI coding agents that ranks relevant repo files and builds compact task-focused context packs for Claude Code, Codex, Cursor, Windsurf, MCP, and CI workflows."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """AgentPack — task-aware context packing for AI coding agents."""
2
2
 
3
- __version__ = "0.3.22"
3
+ __version__ = "0.3.23"
@@ -64,6 +64,16 @@ jobs:
64
64
  - run: python -m pip install -e ".[dev]"
65
65
  - run: python -m agentpack.cli dev-check
66
66
 
67
+ loop-smoke:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - uses: actions/setup-python@v5
72
+ with:
73
+ python-version: "3.11"
74
+ - run: python -m pip install -e ".[dev]"
75
+ - run: python -m agentpack.cli loop-smoke --json
76
+
67
77
  release-gate:
68
78
  runs-on: ubuntu-latest
69
79
  if: github.event_name == 'push'
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import subprocess
5
+ import tempfile
5
6
  from pathlib import Path
6
7
  from typing import Any
7
8
 
@@ -17,6 +18,7 @@ from agentpack.core.loop_protocol import (
17
18
  initialize_loop,
18
19
  load_loop_state,
19
20
  mark_done,
21
+ resolve_runner_adapter,
20
22
  run_loop,
21
23
  )
22
24
  from agentpack.core.thread_context import resolve_thread_option
@@ -35,11 +37,13 @@ def register(app: typer.Typer) -> None:
35
37
  pack_only: bool = typer.Option(False, "--pack-only", help="Run pack directly instead of guard."),
36
38
  no_init: bool = typer.Option(False, "--no-init", help="Do not initialize the repo when .agentpack/config.toml is missing."),
37
39
  no_next: bool = typer.Option(False, "--no-next", help="Do not print next-step diagnostics after context refresh."),
38
- run_loop_requested: bool = typer.Option(False, "--run", help="Run the configured Ralph Loop after preparing context."),
39
- dry_run: bool = typer.Option(False, "--dry-run", help="Plan Ralph Loop execution without running the configured runner."),
40
- runner: str = typer.Option("", "--runner", help="Generic shell command for the Ralph Loop runner."),
40
+ run_loop_requested: bool = typer.Option(False, "--run", help="Run the optional guarded loop after preparing context."),
41
+ dry_run: bool = typer.Option(False, "--dry-run", help="Plan guarded-loop execution without running the configured runner."),
42
+ runner: str = typer.Option("", "--runner", help="Generic shell command for the optional guarded-loop runner."),
43
+ runner_adapter: str = typer.Option("", "--runner-adapter", help="Resolve runner command from a known adapter: claude, codex, cursor."),
41
44
  max_iterations: int = typer.Option(0, "--max-iterations", help="Override [loop].max_iterations for this run."),
42
- verify: list[str] = typer.Option([], "--verify", help="Verification command for Ralph Loop. Repeatable."),
45
+ verify: list[str] = typer.Option([], "--verify", help="Verification command for the guarded loop. Repeatable."),
46
+ acceptance: list[str] = typer.Option([], "--acceptance", help="Semantic acceptance check for runner contract. Repeatable."),
43
47
  json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
44
48
  ) -> None:
45
49
  """Initialize if needed, write a task, refresh context, and show next steps."""
@@ -73,10 +77,13 @@ def register(app: typer.Typer) -> None:
73
77
  root,
74
78
  task_text,
75
79
  cfg.loop,
76
- runner_override=runner,
80
+ runner_override=runner or _resolve_runner_adapter(runner_adapter, root),
77
81
  max_iterations_override=max_iterations,
78
82
  verification_overrides=list(verify) if verify else None,
83
+ acceptance_overrides=list(acceptance) if acceptance else None,
79
84
  )
85
+ if runner_adapter:
86
+ state.runner_adapter = runner_adapter
80
87
  if dry_run:
81
88
  loop_plan = dry_run_plan(root, state).model_dump(mode="json")
82
89
  _finish(stages, json_output, loop_plan=loop_plan)
@@ -105,6 +112,7 @@ def register(app: typer.Typer) -> None:
105
112
  skip_benchmark_capture: bool = typer.Option(False, "--skip-benchmark-capture", help="Skip benchmark case capture."),
106
113
  archive_thread: bool = typer.Option(False, "--archive-thread", help="Archive the thread after marking state done."),
107
114
  allow_empty_capture: bool = typer.Option(False, "--allow-empty-capture", help="Allow benchmark capture with no expected files."),
115
+ allow_high_risk: bool = typer.Option(False, "--allow-high-risk", help="Allow finish after inspecting a high-risk Ralph Loop diff."),
108
116
  json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
109
117
  ) -> None:
110
118
  """Run finish checks, capture benchmark evidence, and mark work done."""
@@ -115,7 +123,7 @@ def register(app: typer.Typer) -> None:
115
123
  finish_task = task or _read_task(root, thread) or (loop_state.task if loop_state else "")
116
124
  loop_applies = loop_state is not None and cfg.loop.enabled and (not finish_task or finish_task == loop_state.task)
117
125
  if loop_applies:
118
- blockers = _loop_finish_blockers(root, cfg.loop, loop_state, thread)
126
+ blockers = _loop_finish_blockers(root, cfg.loop, loop_state, thread, allow_empty_diff=allow_empty_capture, allow_high_risk=allow_high_risk)
119
127
  if blockers:
120
128
  _finish_blocked(blockers, json_output)
121
129
  raise typer.Exit(1)
@@ -146,6 +154,106 @@ def register(app: typer.Typer) -> None:
146
154
  stages.append(_run("threads-archive", cli_module_argv("threads", "archive", thread_id, "--summary", summary), root))
147
155
  _finish(stages, json_output)
148
156
 
157
+ @app.command("loop-smoke")
158
+ def loop_smoke(
159
+ runner: str = typer.Option("", "--runner", help="Runner command to test against a tiny fixture repo."),
160
+ runner_adapter: str = typer.Option("", "--runner-adapter", help="Resolve runner command from a known adapter."),
161
+ json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
162
+ ) -> None:
163
+ """Run an optional guarded-loop smoke test in a temporary fixture repo."""
164
+ with tempfile.TemporaryDirectory(prefix="agentpack-loop-smoke-") as raw:
165
+ root = Path(raw)
166
+ _seed_loop_smoke_repo(root)
167
+ resolved_runner = runner or _resolve_runner_adapter(runner_adapter, root) or _deterministic_smoke_runner(root)
168
+ state = initialize_loop(
169
+ root,
170
+ "make the smoke test pass by changing app.py value to 2",
171
+ load_config(root).loop,
172
+ runner_override=resolved_runner,
173
+ verification_overrides=["python -m pytest -q"],
174
+ acceptance_overrides=["smoke test passes"],
175
+ max_iterations_override=2,
176
+ )
177
+ summary = run_loop(root, state, refresh=lambda: LoopCommandResult(command="smoke-refresh", returncode=0, output_excerpt="ok"))
178
+ payload = {
179
+ "passed": summary.status == "ready_to_finish",
180
+ "summary": summary.model_dump(mode="json"),
181
+ "runner": resolved_runner,
182
+ }
183
+ latest = load_loop_state(root)
184
+ if latest is not None and latest.last_runner is not None:
185
+ payload["runner_output_excerpt"] = latest.last_runner.output_excerpt
186
+ if latest is not None:
187
+ payload["failure_class"] = latest.failure_class
188
+ if json_output:
189
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
190
+ else:
191
+ marker = "[green]✓[/]" if payload["passed"] else "[red]✗[/]"
192
+ console.print(f"{marker} loop smoke {summary.status}")
193
+ console.print(f"runner: [bold]{resolved_runner}[/]")
194
+ if summary.status != "ready_to_finish":
195
+ raise typer.Exit(1)
196
+
197
+ @app.command("loop-rollback")
198
+ def loop_rollback(
199
+ iteration: int = typer.Option(0, "--iteration", help="Rollback patch iteration (0 = latest recorded)."),
200
+ json_output: bool = typer.Option(False, "--json", help="Emit JSON."),
201
+ ) -> None:
202
+ """Restore the worktree to the latest recorded guarded-loop rollback patch."""
203
+ root = _root()
204
+ state = load_loop_state(root)
205
+ patch = _loop_rollback_patch(root, state, iteration)
206
+ payload = {"patch": str(patch.relative_to(root)) if patch else "", "applied": False}
207
+ current = subprocess.run(["git", "diff", "--binary"], cwd=root, capture_output=True, text=True)
208
+ if current.stdout.strip():
209
+ reverse = subprocess.run(["git", "apply", "-R", "-"], input=current.stdout, cwd=root, capture_output=True, text=True)
210
+ if reverse.returncode != 0:
211
+ payload["reason"] = reverse.stderr.strip() or "failed to reverse current diff"
212
+ if json_output:
213
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
214
+ return
215
+ console.print(f"[red]Rollback failed:[/] {payload['reason']}")
216
+ raise typer.Exit(1)
217
+ payload["applied"] = True
218
+ elif not patch:
219
+ payload["reason"] = "no rollback patch found and worktree has no tracked diff"
220
+ if json_output:
221
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
222
+ return
223
+ console.print("[yellow]No rollback patch found and worktree has no tracked diff.[/]")
224
+ return
225
+ if not patch:
226
+ if json_output:
227
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
228
+ return
229
+ console.print("[green]✓[/] Reversed current tracked diff")
230
+ return
231
+ apply_result = subprocess.run(["git", "apply", str(patch)], cwd=root, capture_output=True, text=True)
232
+ payload["applied"] = apply_result.returncode == 0
233
+ if apply_result.returncode != 0:
234
+ payload["reason"] = apply_result.stderr.strip() or "failed to apply rollback patch"
235
+ if json_output:
236
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
237
+ return
238
+ console.print(f"[red]Rollback failed:[/] {payload['reason']}")
239
+ raise typer.Exit(1)
240
+ if json_output:
241
+ typer.echo(json.dumps(payload, indent=2, sort_keys=True))
242
+ return
243
+ console.print(f"[green]✓[/] Applied rollback patch {payload['patch']}")
244
+
245
+ @app.command("loop-metrics")
246
+ def loop_metrics(json_output: bool = typer.Option(False, "--json", help="Emit JSON.")) -> None:
247
+ """Summarize guarded-loop outcomes over time."""
248
+ root = _root()
249
+ rows = _read_loop_metrics(root)
250
+ summary = _summarize_loop_metrics(rows)
251
+ if json_output:
252
+ typer.echo(json.dumps(summary, indent=2, sort_keys=True))
253
+ return
254
+ console.print(f"Runs: [bold]{summary['runs']}[/]")
255
+ console.print(f"Ready: [green]{summary['ready_to_finish']}[/] Blocked: [yellow]{summary['blocked']}[/] Done: [green]{summary['done']}[/]")
256
+
149
257
 
150
258
  def _run(name: str, command: list[str], root: Path) -> dict[str, Any]:
151
259
  result = subprocess.run(command, cwd=root, capture_output=True, text=True)
@@ -190,8 +298,19 @@ def _finish(
190
298
  raise typer.Exit(1)
191
299
 
192
300
 
193
- def _loop_finish_blockers(root: Path, loop_cfg, loop_state, thread: str) -> list[dict[str, Any]]:
194
- blockers = [blocker.model_dump(mode="json") for blocker in finish_blockers(root, loop_cfg, loop_state)]
301
+ def _loop_finish_blockers(
302
+ root: Path,
303
+ loop_cfg,
304
+ loop_state,
305
+ thread: str,
306
+ *,
307
+ allow_empty_diff: bool = False,
308
+ allow_high_risk: bool = False,
309
+ ) -> list[dict[str, Any]]:
310
+ blockers = [
311
+ blocker.model_dump(mode="json")
312
+ for blocker in finish_blockers(root, loop_cfg, loop_state, allow_empty_diff=allow_empty_diff, allow_high_risk=allow_high_risk)
313
+ ]
195
314
  fresh, reason = _context_is_fresh(root, thread_id=resolve_thread_option(thread))
196
315
  if not fresh:
197
316
  blockers.append(
@@ -204,6 +323,94 @@ def _loop_finish_blockers(root: Path, loop_cfg, loop_state, thread: str) -> list
204
323
  return blockers
205
324
 
206
325
 
326
+ def _resolve_runner_adapter(adapter: str, root: Path) -> str:
327
+ if not adapter:
328
+ return ""
329
+ command = resolve_runner_adapter(adapter, root)
330
+ if not command:
331
+ console.print(f"[red]Runner adapter unavailable:[/] {adapter}")
332
+ raise typer.Exit(1)
333
+ return command
334
+
335
+
336
+ def _seed_loop_smoke_repo(root: Path) -> None:
337
+ subprocess.run(["git", "init"], cwd=root, check=True, capture_output=True, text=True)
338
+ (root / ".agentpack").mkdir()
339
+ (root / ".agentpack" / "config.toml").write_text("[context]\n[loop]\nrequire_clean_tree = false\n", encoding="utf-8")
340
+ (root / ".agentpack" / "task.md").write_text("make smoke test pass\n", encoding="utf-8")
341
+ (root / "app.py").write_text("VALUE = 1\n", encoding="utf-8")
342
+ (root / "test_app.py").write_text("from app import VALUE\n\n\ndef test_value():\n assert VALUE == 2\n", encoding="utf-8")
343
+ subprocess.run(["git", "add", "app.py", "test_app.py"], cwd=root, check=True, capture_output=True, text=True)
344
+ subprocess.run(
345
+ ["git", "-c", "user.email=test@example.com", "-c", "user.name=Test User", "commit", "-m", "init"],
346
+ cwd=root,
347
+ check=True,
348
+ capture_output=True,
349
+ text=True,
350
+ )
351
+
352
+
353
+ def _deterministic_smoke_runner(root: Path) -> str:
354
+ script = root / "smoke_runner.py"
355
+ script.write_text(
356
+ "from pathlib import Path\n"
357
+ "Path('app.py').write_text('VALUE = 2\\n', encoding='utf-8')\n"
358
+ "print('{\"status\":\"changed\",\"summary\":\"updated app.py\",\"files_changed\":[\"app.py\"],\"acceptance\":{\"smoke test passes\":\"pass\"}}')\n",
359
+ encoding="utf-8",
360
+ )
361
+ return "python smoke_runner.py"
362
+
363
+
364
+ def _loop_rollback_patch(root: Path, state, iteration: int) -> Path | None:
365
+ if iteration > 0:
366
+ candidate = root / ".agentpack" / "loop_rollback" / f"iteration-{iteration}-before.patch"
367
+ return candidate if candidate.exists() else None
368
+ if state is not None and state.rollback_patch:
369
+ candidate = root / state.rollback_patch
370
+ if candidate.exists():
371
+ return candidate
372
+ patches = sorted((root / ".agentpack" / "loop_rollback").glob("iteration-*-before.patch"))
373
+ return patches[-1] if patches else None
374
+
375
+
376
+ def _read_loop_metrics(root: Path) -> list[dict[str, Any]]:
377
+ path = root / ".agentpack" / "loop_metrics.jsonl"
378
+ if not path.exists():
379
+ return []
380
+ rows: list[dict[str, Any]] = []
381
+ for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
382
+ try:
383
+ value = json.loads(line)
384
+ except json.JSONDecodeError:
385
+ continue
386
+ if isinstance(value, dict):
387
+ rows.append(value)
388
+ return rows[-500:]
389
+
390
+
391
+ def _summarize_loop_metrics(rows: list[dict[str, Any]]) -> dict[str, Any]:
392
+ outcomes: dict[str, int] = {}
393
+ failure_classes: dict[str, int] = {}
394
+ total_iterations = 0
395
+ for row in rows:
396
+ outcome = str(row.get("outcome") or "unknown")
397
+ outcomes[outcome] = outcomes.get(outcome, 0) + 1
398
+ failure_class = str(row.get("failure_class") or "")
399
+ if failure_class:
400
+ failure_classes[failure_class] = failure_classes.get(failure_class, 0) + 1
401
+ total_iterations += int(row.get("iterations") or 0)
402
+ runs = len(rows)
403
+ return {
404
+ "runs": runs,
405
+ "ready_to_finish": outcomes.get("ready_to_finish", 0),
406
+ "blocked": outcomes.get("blocked", 0),
407
+ "done": outcomes.get("done", 0),
408
+ "outcomes": outcomes,
409
+ "failure_classes": failure_classes,
410
+ "avg_iterations": round(total_iterations / runs, 2) if runs else 0,
411
+ }
412
+
413
+
207
414
  def _finish_blocked(blockers: list[dict[str, Any]], json_output: bool) -> None:
208
415
  if json_output:
209
416
  typer.echo(json.dumps({"passed": False, "stages": [], "loop_blockers": blockers}, indent=2, sort_keys=True))
@@ -76,8 +76,11 @@ class LearningConfig(BaseModel):
76
76
  class LoopConfig(BaseModel):
77
77
  enabled: bool = True
78
78
  runner: str = ""
79
+ runner_adapter: str = ""
80
+ runner_prompt_output: str = ".agentpack/loop_runner_prompt.md"
79
81
  max_iterations: int = 10
80
82
  verification_commands: list[str] = Field(default_factory=list)
83
+ acceptance_checks: list[str] = Field(default_factory=list)
81
84
  require_verification: bool = True
82
85
  require_progress_update: bool = True
83
86
  require_clean_tree: bool = True
@@ -86,6 +89,8 @@ class LoopConfig(BaseModel):
86
89
  runner_timeout_seconds: int = 600
87
90
  verification_timeout_seconds: int = 600
88
91
  max_repeated_failures: int = 3
92
+ risk_sensitive_globs: list[str] = Field(default_factory=list)
93
+ risk_high_file_count: int = 20
89
94
 
90
95
 
91
96
  class RuntimeConfig(BaseModel):