agex-cli 0.22.0__tar.gz → 0.24.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 (220) hide show
  1. {agex_cli-0.22.0 → agex_cli-0.24.0}/.github/workflows/publish.yml +19 -13
  2. {agex_cli-0.22.0 → agex_cli-0.24.0}/CHANGELOG.md +28 -0
  3. {agex_cli-0.22.0 → agex_cli-0.24.0}/CLAUDE.md +3 -3
  4. {agex_cli-0.22.0 → agex_cli-0.24.0}/PKG-INFO +6 -6
  5. agex_cli-0.24.0/README.md +29 -0
  6. {agex_cli-0.22.0 → agex_cli-0.24.0}/pyproject.toml +4 -3
  7. {agex_cli-0.22.0 → agex_cli-0.24.0}/sonar-project.properties +2 -2
  8. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/__init__.py +8 -7
  9. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/cli.py +48 -15
  10. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/assets/report.md.j2 +2 -2
  11. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/scripts/doctor.py +12 -9
  12. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/assets/topics/agex.md +1 -1
  13. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/scripts/explain.py +2 -1
  14. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/scripts/install.py +7 -5
  15. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/scripts/write.py +2 -1
  16. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/menu.md.j2 +1 -1
  17. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/scripts/learn.py +3 -2
  18. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/SKILL.md +24 -3
  19. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/backends/acp.yaml +21 -0
  20. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/backends/claude-code.yaml +21 -0
  21. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/backends/codex.yaml +21 -0
  22. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/backends/copilot.yaml +21 -0
  23. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/rules/next_step_rules.py +4 -0
  24. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/delta.md.j2 +1 -1
  25. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/lint_result.md.j2 +2 -2
  26. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/pr_briefing.md.j2 +1 -1
  27. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/templates/pr_open_result.md.j2 +17 -0
  28. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/pr_reply_result.md.j2 +1 -1
  29. agex_cli-0.24.0/src/agent_experience/commands/pr/assets/templates/pr_review_result.md.j2 +5 -0
  30. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/_readiness.py +5 -1
  31. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/await_.py +1 -10
  32. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/delta.py +4 -2
  33. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/open_.py +23 -1
  34. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/read.py +1 -10
  35. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/reply.py +6 -4
  36. agex_cli-0.24.0/src/agent_experience/commands/pr/scripts/review.py +59 -0
  37. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/capabilities.py +1 -1
  38. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/github.py +15 -0
  39. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/hook_io.py +1 -1
  40. agex_cli-0.24.0/src/agent_experience/core/prog.py +44 -0
  41. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/render.py +9 -1
  42. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_footer.py +16 -0
  43. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_open.py +90 -0
  44. agex_cli-0.24.0/tests/commands/pr/test_review.py +97 -0
  45. agex_cli-0.24.0/tests/commands/test_prog_propagation.py +45 -0
  46. agex_cli-0.24.0/tests/core/test_prog.py +39 -0
  47. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_version_lookup.py +13 -6
  48. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/test_cli_dispatch.py +11 -0
  49. {agex_cli-0.22.0 → agex_cli-0.24.0}/uv.lock +1 -1
  50. agex_cli-0.22.0/README.md +0 -29
  51. agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/acp.yaml +0 -20
  52. agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/claude-code.yaml +0 -20
  53. agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/codex.yaml +0 -20
  54. agex_cli-0.22.0/src/agent_experience/commands/pr/assets/backends/copilot.yaml +0 -20
  55. agex_cli-0.22.0/src/agent_experience/commands/pr/assets/templates/pr_open_result.md.j2 +0 -13
  56. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/agent-config/SKILL.md +0 -0
  57. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
  58. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
  59. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
  60. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
  61. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/cicd/SKILL.md +0 -0
  62. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
  63. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/communicate/SKILL.md +0 -0
  64. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
  65. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
  66. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
  67. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
  68. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
  69. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
  70. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
  71. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
  72. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/run-tests/SKILL.md +0 -0
  73. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  74. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
  75. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
  76. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
  77. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
  78. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/think/SKILL.md +0 -0
  79. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/think/scripts/think.sh +0 -0
  80. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/version-bump/SKILL.md +0 -0
  81. {agex_cli-0.22.0 → agex_cli-0.24.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
  82. {agex_cli-0.22.0 → agex_cli-0.24.0}/.flake8 +0 -0
  83. {agex_cli-0.22.0 → agex_cli-0.24.0}/.github/workflows/test.yml +0 -0
  84. {agex_cli-0.22.0 → agex_cli-0.24.0}/.gitignore +0 -0
  85. {agex_cli-0.22.0 → agex_cli-0.24.0}/.python-version +0 -0
  86. {agex_cli-0.22.0 → agex_cli-0.24.0}/LICENSE +0 -0
  87. {agex_cli-0.22.0 → agex_cli-0.24.0}/culture.yaml +0 -0
  88. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/skill-sources.md +0 -0
  89. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/superpowers/plans/2026-04-18-agex-v0.1.md +0 -0
  90. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/superpowers/plans/2026-05-10-agex-pr.md +0 -0
  91. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/superpowers/specs/2026-04-18-agex-design.md +0 -0
  92. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/superpowers/specs/2026-04-26-agex-doctor.md +0 -0
  93. {agex_cli-0.22.0 → agex_cli-0.24.0}/docs/superpowers/specs/2026-05-10-agex-pr-design.md +0 -0
  94. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/__main__.py +0 -0
  95. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/__init__.py +0 -0
  96. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/acp/__init__.py +0 -0
  97. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/acp/probe.py +0 -0
  98. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/capabilities/acp.yaml +0 -0
  99. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/capabilities/claude-code.yaml +0 -0
  100. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/capabilities/codex.yaml +0 -0
  101. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/capabilities/copilot.yaml +0 -0
  102. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/claude_code/__init__.py +0 -0
  103. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/claude_code/probe.py +0 -0
  104. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/codex/__init__.py +0 -0
  105. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/codex/probe.py +0 -0
  106. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/copilot/__init__.py +0 -0
  107. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/backends/copilot/probe.py +0 -0
  108. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/__init__.py +0 -0
  109. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/SKILL.md +0 -0
  110. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/__init__.py +0 -0
  111. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/references/design.md +0 -0
  112. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/doctor/scripts/__init__.py +0 -0
  113. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/SKILL.md +0 -0
  114. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/__init__.py +0 -0
  115. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/references/.gitkeep +0 -0
  116. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/explain/scripts/__init__.py +0 -0
  117. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/SKILL.md +0 -0
  118. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/__init__.py +0 -0
  119. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/assets/hooks/claude-code.json +0 -0
  120. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/references/.gitkeep +0 -0
  121. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/gamify/scripts/__init__.py +0 -0
  122. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/SKILL.md +0 -0
  123. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/__init__.py +0 -0
  124. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/assets/table.md.j2 +0 -0
  125. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/references/.gitkeep +0 -0
  126. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/scripts/__init__.py +0 -0
  127. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/hook/scripts/read.py +0 -0
  128. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/SKILL.md +0 -0
  129. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/__init__.py +0 -0
  130. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/cicd/SKILL.md +0 -0
  131. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/gamify/SKILL.md +0 -0
  132. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/gamify/assets/skill-template/claude-code/SKILL.md +0 -0
  133. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/introspect/SKILL.md +0 -0
  134. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/introspect/assets/skill-template/claude-code/SKILL.md +0 -0
  135. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/levelup/SKILL.md +0 -0
  136. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/levelup/assets/skill-template/claude-code/SKILL.md +0 -0
  137. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/visualize/SKILL.md +0 -0
  138. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/assets/topics/visualize/assets/skill-template/claude-code/SKILL.md +0 -0
  139. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/references/.gitkeep +0 -0
  140. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/learn/scripts/__init__.py +0 -0
  141. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/SKILL.md +0 -0
  142. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/__init__.py +0 -0
  143. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/assets/backends/acp.yaml +0 -0
  144. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/assets/backends/claude-code.yaml +0 -0
  145. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/assets/backends/codex.yaml +0 -0
  146. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/assets/backends/copilot.yaml +0 -0
  147. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/assets/sections.md.j2 +0 -0
  148. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/references/.gitkeep +0 -0
  149. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/scripts/__init__.py +0 -0
  150. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/overview/scripts/overview.py +0 -0
  151. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/__init__.py +0 -0
  152. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/__init__.py +0 -0
  153. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/backends/__init__.py +0 -0
  154. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/rules/__init__.py +0 -0
  155. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/rules/lint_rules.py +0 -0
  156. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/__init__.py +0 -0
  157. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/assets/templates/footer.md.j2 +0 -0
  158. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/__init__.py +0 -0
  159. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/_footer.py +0 -0
  160. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/_journal.py +0 -0
  161. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/_qodo.py +0 -0
  162. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/_sonar.py +0 -0
  163. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/commands/pr/scripts/lint.py +0 -0
  164. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/__init__.py +0 -0
  165. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/backend.py +0 -0
  166. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/config.py +0 -0
  167. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/journal.py +0 -0
  168. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/paths.py +0 -0
  169. {agex_cli-0.22.0 → agex_cli-0.24.0}/src/agent_experience/core/skill_loader.py +0 -0
  170. {agex_cli-0.22.0 → agex_cli-0.24.0}/tester-agents/claude/.claude/settings.json +0 -0
  171. {agex_cli-0.22.0 → agex_cli-0.24.0}/tester-agents/claude/CLAUDE.md +0 -0
  172. {agex_cli-0.22.0 → agex_cli-0.24.0}/tester-agents/claude/README.md +0 -0
  173. {agex_cli-0.22.0 → agex_cli-0.24.0}/tester-agents/claude/culture.yaml +0 -0
  174. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/__init__.py +0 -0
  175. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/backends/__init__.py +0 -0
  176. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/backends/test_claude_code_probe.py +0 -0
  177. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/backends/test_stub_probes.py +0 -0
  178. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/__init__.py +0 -0
  179. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/__init__.py +0 -0
  180. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/fixtures/gh/.gitkeep +0 -0
  181. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/fixtures/gh/pr_checks_42.json +0 -0
  182. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/fixtures/gh/pr_comments_42.json +0 -0
  183. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/fixtures/gh/qodo_summary_comment.html +0 -0
  184. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/fixtures/journals/dogfood_40.jsonl +0 -0
  185. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_await.py +0 -0
  186. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_delta.py +0 -0
  187. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_lint.py +0 -0
  188. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_lint_rules.py +0 -0
  189. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_qodo.py +0 -0
  190. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_read.py +0 -0
  191. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/pr/test_reply.py +0 -0
  192. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_doctor.py +0 -0
  193. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_explain.py +0 -0
  194. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_gamify.py +0 -0
  195. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_hook.py +0 -0
  196. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_learn.py +0 -0
  197. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/commands/test_overview.py +0 -0
  198. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/__init__.py +0 -0
  199. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_backend.py +0 -0
  200. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_capabilities.py +0 -0
  201. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_config.py +0 -0
  202. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_github.py +0 -0
  203. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_hook_io.py +0 -0
  204. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_journal.py +0 -0
  205. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_paths.py +0 -0
  206. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_render.py +0 -0
  207. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_resolve_backend.py +0 -0
  208. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/core/test_skill_loader.py +0 -0
  209. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/empty/.gitkeep +0 -0
  210. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/malformed/.claude/hooks.json +0 -0
  211. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/malformed/.claude/settings.json +0 -0
  212. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/malformed/.claude/skills/bad/SKILL.md +0 -0
  213. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/malformed/.claude/skills/broken-yaml/SKILL.md +0 -0
  214. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/typical/.claude/hooks.json +0 -0
  215. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/typical/.claude/settings.json +0 -0
  216. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/typical/.claude/skills/example/SKILL.md +0 -0
  217. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/fixtures/claude-code/typical/CLAUDE.md +0 -0
  218. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/test_cli_errors.py +0 -0
  219. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/test_cli_smoke.py +0 -0
  220. {agex_cli-0.22.0 → agex_cli-0.24.0}/tests/test_skill_md_consistency.py +0 -0
@@ -27,15 +27,20 @@ name: publish
27
27
  # One-time setup on pypi.org / test.pypi.org and in the repo's Environments
28
28
  # (`pypi`, `testpypi`) is documented in the original header below:
29
29
  #
30
- # - PyPI project `agex-cli` → Publishing → Add a GitHub pending publisher
31
- # Owner: OriNachum Repo: agex
30
+ # - For EACH PyPI project (`agex-cli`, `agent-devex`, `devex-cli`)
31
+ # Publishing → Add a GitHub pending publisher
32
+ # Owner: agentculture Repo: devex
32
33
  # Workflow: publish.yml Environment: pypi
33
34
  #
34
- # - TestPyPI project `agex-cli` same shape, Environment: testpypi
35
+ # - Same for EACH TestPyPI project, Environment: testpypi
35
36
  #
36
37
  # - GitHub repo → Settings → Environments → create `pypi` and `testpypi`
37
38
  # (any required reviewers / wait timers live there)
38
39
  #
40
+ # NOTE: the repo was renamed agentculture/agex-cli → agentculture/devex.
41
+ # The pre-existing `agex-cli` / `agent-devex` publishers must have their
42
+ # Repo updated to `devex` too, or those legs start failing OIDC.
43
+ #
39
44
  # The PR job rewrites `version = "X.Y.Z"` to `"X.Y.Z.devN"` where N is
40
45
  # the workflow run number. PEP 440's dev segment is a single integer
41
46
  # (internal dots aren't allowed), so run_attempt is NOT encoded in the
@@ -67,10 +72,11 @@ jobs:
67
72
  # pull_request -- the PR path has its own build inside `publish-pr-testpypi`
68
73
  # because it needs to rewrite the version before building.
69
74
  #
70
- # The matrix exists so we can publish the same code under two PyPI
71
- # distribution names: `agex-cli` (canonical) and `agent-devex` (alias).
72
- # Each leg rewrites `[project].name` in pyproject.toml before building so
73
- # each wheel is uploaded under its own Trusted Publishing project.
75
+ # The matrix exists so we can publish the same code under three PyPI
76
+ # distribution names: `agex-cli` (canonical) plus the `agent-devex` and
77
+ # `devex-cli` aliases. Each leg rewrites `[project].name` in pyproject.toml
78
+ # before building so each wheel is uploaded under its own Trusted Publishing
79
+ # project.
74
80
  # --------------------------------------------------------------------------
75
81
  build:
76
82
  if: github.event_name == 'push'
@@ -78,7 +84,7 @@ jobs:
78
84
  strategy:
79
85
  fail-fast: false
80
86
  matrix:
81
- dist_name: [agex-cli, agent-devex]
87
+ dist_name: [agex-cli, agent-devex, devex-cli]
82
88
  permissions:
83
89
  contents: read # actions/checkout
84
90
  steps:
@@ -93,8 +99,8 @@ jobs:
93
99
 
94
100
  # Rewrite `[project].name` to the matrix dist name. For `agex-cli`
95
101
  # (the canonical dist) the regex still has to match so we re-emit
96
- # the line; for `agent-devex` it produces an alias dist with
97
- # identical contents. The post-rewrite re-parse is a fail-closed
102
+ # the line; for `agent-devex` / `devex-cli` it produces an alias dist
103
+ # with identical contents. The post-rewrite re-parse is a fail-closed
98
104
  # check: if a future formatting change breaks the regex match (or
99
105
  # `[project].name` ends up wrong for any reason), the job aborts
100
106
  # before uploading mis-named artifacts.
@@ -150,7 +156,7 @@ jobs:
150
156
  strategy:
151
157
  fail-fast: false
152
158
  matrix:
153
- dist_name: [agex-cli, agent-devex]
159
+ dist_name: [agex-cli, agent-devex, devex-cli]
154
160
  environment: testpypi
155
161
  permissions:
156
162
  id-token: write # OIDC -- Trusted Publishing
@@ -273,7 +279,7 @@ jobs:
273
279
  strategy:
274
280
  fail-fast: false
275
281
  matrix:
276
- dist_name: [agex-cli, agent-devex]
282
+ dist_name: [agex-cli, agent-devex, devex-cli]
277
283
  environment: testpypi
278
284
  permissions:
279
285
  id-token: write # OIDC; no API token needed
@@ -372,7 +378,7 @@ jobs:
372
378
  strategy:
373
379
  fail-fast: false
374
380
  matrix:
375
- dist_name: [agex-cli, agent-devex]
381
+ dist_name: [agex-cli, agent-devex, devex-cli]
376
382
  environment: pypi
377
383
  permissions:
378
384
  id-token: write # OIDC; no API token needed
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.24.0] - 2026-05-28
11
+
12
+ ### Added
13
+
14
+ - `agex pr review [<PR>]` verb — posts the Qodo agentic-review trigger (`/agentic_review`) on demand; re-triggers a review on an existing PR or triggers a draft once ready.
15
+ - `agex pr open` now auto-posts `/agentic_review` out of the box for a freshly created, non-draft PR (skipped for drafts and already-open PRs) so the review trigger is never hand-typed (#60).
16
+
17
+ ### Changed
18
+
19
+ - Centralized the Qodo review-trigger command string in one place (`commands/pr/scripts/review.QODO_REVIEW_TRIGGER`). agex emits the current `/agentic_review`; the legacy `/improve` command is deprecated by Qodo and is never emitted by agex (#60).
20
+
21
+ ## [0.23.0] - 2026-05-28
22
+
23
+ ### Added
24
+
25
+ - `devex` console command — second entry point alongside `agex`; both invoke the same CLI and emitted output (Next-step footers, briefing/template headers, error prefixes) reflects whichever name was typed, via the new single-source-of-truth `core.prog.prog_name()` injected into the render context.
26
+ - Third PyPI distribution name `devex-cli` — the same wheel now publishes under `agex-cli` (canonical), `agent-devex`, and `devex-cli`; version resolution and the publish matrices cover all three.
27
+
28
+ ### Changed
29
+
30
+ - Repo renamed `agentculture/agex-cli` → `agentculture/devex`; updated in-code issue/repo URLs, README, CLAUDE.md, and the publish workflow OIDC setup notes.
31
+ - SonarCloud project key → `agentculture_devex` (display name `devex`; organization unchanged).
32
+
33
+ ### Fixed
34
+
35
+ - "Output follows invocation" now also covers **plain-string** stdout/stderr in command scripts (`explain`/`learn`/`hook`/`doctor`/`gamify`/`pr delta`/`pr reply` error prefixes, status lines, and command examples), not just Jinja-rendered templates — added `core.prog.error_prefix()` and routed those paths through `prog_name()` (agex-cli#61 Qodo review).
36
+ - `prog_name()` now strips entry-point wrapper suffixes (`.exe`, `.py`, `-script`) before matching, so a real `devex` invocation via the Windows console script `devex.exe` no longer falls back to `agex` (agex-cli#61 Qodo review).
37
+
10
38
  ## [0.22.0] - 2026-05-25
11
39
 
12
40
  ### Added
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
 
5
5
  ## Project
6
6
 
7
- `agex` — non-agentic Python CLI that emits deterministic per-backend markdown briefings for autonomous agents. PyPI distribution name: `agex-cli`. CLI entry point: `agex`. GitHub repo: `agentculture/agex-cli`. Python module (unchanged): `agent_experience`.
7
+ `agex` — non-agentic Python CLI that emits deterministic per-backend markdown briefings for autonomous agents. Published on PyPI under three distribution names: `agex-cli` (canonical), `agent-devex`, and `devex-cli` — the same wheel each time. CLI entry points: `agex` and `devex` (both invoke the same tool; emitted output reflects whichever name was typed). GitHub repo: `agentculture/devex`. Python module (unchanged): `agent_experience`.
8
8
 
9
9
  **Source-of-truth documents:**
10
10
 
@@ -19,7 +19,7 @@ Read the spec before any non-trivial change — the design invariants below are
19
19
  1. **Zero LLM calls inside agex.** All output is deterministic markdown from Jinja templates + Python.
20
20
  2. **Markdown is the only output format.** No `--json` flag.
21
21
  3. **`--agent <backend>` is required** on backend-sensitive commands. The CLI never auto-detects.
22
- 4. **Side effects only in** `gamify`, `gamify --uninstall`, `hook write`, `pr open`, `pr reply`, `pr read` (journal writes), and first-run `.agex/` init. Everything else is read-only. The `agex pr` namespace allows scoped network I/O (via `gh`) and bounded `--wait` sleep — a deliberate carve-out from the no-network/no-sleep invariants.
22
+ 4. **Side effects only in** `gamify`, `gamify --uninstall`, `hook write`, `pr open`, `pr reply`, `pr review`, `pr read` (journal writes), and first-run `.agex/` init. Everything else is read-only. The `agex pr` namespace allows scoped network I/O (via `gh`) and bounded `--wait` sleep — a deliberate carve-out from the no-network/no-sleep invariants.
23
23
  5. **"Unsupported" is success** — exit 0 with a markdown notice that links to the issue tracker, not a non-zero exit.
24
24
  6. **Skills are authored by the agent, not shipped by agex.** `agex learn <topic>` teaches; `agex explain <topic>` describes; agex never writes a user skill file on the agent's behalf in v0.1.
25
25
 
@@ -43,7 +43,7 @@ cli.py ──► commands/<name>/scripts/<name>.py ──► core/render.py
43
43
 
44
44
  ## `agex pr` namespace (v0.17.0+)
45
45
 
46
- `lint`, `open`, `read`, `reply`, `delta`. Each command ends with a deterministic "Next step:" footer. The `pr` namespace allows scoped network I/O (via `gh`) and bounded `--wait` sleep — a deliberate carve-out from the no-network/no-sleep invariants. Key modules:
46
+ `lint`, `open`, `read`, `reply`, `review`, `await`, `delta`. Each command ends with a deterministic "Next step:" footer. The `pr` namespace allows scoped network I/O (via `gh`) and bounded `--wait` sleep — a deliberate carve-out from the no-network/no-sleep invariants. `pr open` (non-draft, new PR) and `pr review` post the Qodo `/agentic_review` trigger comment; the legacy `/improve` is deprecated and never emitted. The trigger string lives in one place: `commands/pr/scripts/review.QODO_REVIEW_TRIGGER`. Key modules:
47
47
 
48
48
  - `core/github.py` — thin `gh` shellout wrapper; future zero-trust httpx swap touches only this file.
49
49
  - `core/journal.py` — nested-stream JSONL append/load for `.agex/data/<dir>/<stream>.jsonl`.
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agex-cli
3
- Version: 0.22.0
3
+ Version: 0.24.0
4
4
  Summary: Agent-operated developer-experience CLI — deterministic per-backend markdown briefings for autonomous agents.
5
5
  Project-URL: Homepage, https://culture.dev/agex/
6
- Project-URL: Repository, https://github.com/agentculture/agex-cli
7
- Project-URL: Issues, https://github.com/agentculture/agex-cli/issues
6
+ Project-URL: Repository, https://github.com/agentculture/devex
7
+ Project-URL: Issues, https://github.com/agentculture/devex/issues
8
8
  Author: Ori Nachum
9
9
  License: MIT
10
10
  License-File: LICENSE
@@ -26,14 +26,14 @@ Description-Content-Type: text/markdown
26
26
 
27
27
  # agex
28
28
 
29
- Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first. Distributed on PyPI as `agex-cli`; installs the `agex` command.
29
+ Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first. The same wheel is published on PyPI under three distribution names — `agex-cli` (canonical), `agent-devex`, and `devex-cli` — and installs two equivalent commands, `agex` and `devex` (emitted output reflects whichever name you invoke).
30
30
 
31
31
  ## Install
32
32
 
33
33
  ```bash
34
- uv tool install agex-cli
34
+ uv tool install agex-cli # or: devex-cli
35
35
  # or
36
- pipx install agex-cli
36
+ pipx install agex-cli # or: pipx install devex-cli
37
37
  ```
38
38
 
39
39
  ## Quick start
@@ -0,0 +1,29 @@
1
+ # agex
2
+
3
+ Agent-operated developer-experience CLI. Non-agentic, deterministic, markdown-first. The same wheel is published on PyPI under three distribution names — `agex-cli` (canonical), `agent-devex`, and `devex-cli` — and installs two equivalent commands, `agex` and `devex` (emitted output reflects whichever name you invoke).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ uv tool install agex-cli # or: devex-cli
9
+ # or
10
+ pipx install agex-cli # or: pipx install devex-cli
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ agex explain agex
17
+ agex overview --agent claude-code
18
+ agex learn --agent claude-code
19
+ ```
20
+
21
+ ## Docs
22
+
23
+ [culture.dev/agex](https://culture.dev/agex/).
24
+
25
+ Spec: `docs/superpowers/specs/2026-04-18-agex-design.md`.
26
+
27
+ ## License
28
+
29
+ MIT.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agex-cli"
3
- version = "0.22.0"
3
+ version = "0.24.0"
4
4
  description = "Agent-operated developer-experience CLI — deterministic per-backend markdown briefings for autonomous agents."
5
5
  authors = [{name = "Ori Nachum"}]
6
6
  license = {text = "MIT"}
@@ -27,11 +27,12 @@ dev = [
27
27
 
28
28
  [project.scripts]
29
29
  agex = "agent_experience.cli:_main_entrypoint"
30
+ devex = "agent_experience.cli:_main_entrypoint"
30
31
 
31
32
  [project.urls]
32
33
  Homepage = "https://culture.dev/agex/"
33
- Repository = "https://github.com/agentculture/agex-cli"
34
- Issues = "https://github.com/agentculture/agex-cli/issues"
34
+ Repository = "https://github.com/agentculture/devex"
35
+ Issues = "https://github.com/agentculture/devex/issues"
35
36
 
36
37
  [build-system]
37
38
  requires = ["hatchling"]
@@ -1,8 +1,8 @@
1
- sonar.projectKey=OriNachum_agex
1
+ sonar.projectKey=agentculture_devex
2
2
  sonar.organization=orinachum
3
3
 
4
4
  # Displayed in SonarCloud UI
5
- sonar.projectName=agex
5
+ sonar.projectName=devex
6
6
 
7
7
  # Source layout
8
8
  sonar.sources=src
@@ -2,13 +2,14 @@ from importlib.metadata import PackageNotFoundError, version
2
2
 
3
3
 
4
4
  def _resolve_version() -> str:
5
- # `agex-cli` is the canonical PyPI distribution name; `agent-devex` is an
6
- # alias distribution that ships the identical wheel under a different name.
7
- # Whichever one is installed, surface its metadata version. As a final
8
- # fallback for unbuilt source checkouts (no installed dist metadata),
9
- # read the version directly from the repo's pyproject.toml so the version
10
- # stays single-sourced from pyproject.toml in every reachable code path.
11
- for dist in ("agex-cli", "agent-devex"):
5
+ # `agex-cli` is the canonical PyPI distribution name; `agent-devex` and
6
+ # `devex-cli` are alias distributions that ship the identical wheel under
7
+ # different names. Whichever one is installed, surface its metadata
8
+ # version. As a final fallback for unbuilt source checkouts (no installed
9
+ # dist metadata), read the version directly from the repo's pyproject.toml
10
+ # so the version stays single-sourced from pyproject.toml in every
11
+ # reachable code path.
12
+ for dist in ("agex-cli", "agent-devex", "devex-cli"):
12
13
  try:
13
14
  return version(dist)
14
15
  except PackageNotFoundError:
@@ -27,12 +27,18 @@ from agent_experience.commands.pr.scripts import lint as pr_lint_script
27
27
  from agent_experience.commands.pr.scripts import open_ as pr_open_script
28
28
  from agent_experience.commands.pr.scripts import read as pr_read_script
29
29
  from agent_experience.commands.pr.scripts import reply as pr_reply_script
30
+ from agent_experience.commands.pr.scripts import review as pr_review_script
30
31
  from agent_experience.core.backend import parse_backend
32
+ from agent_experience.core.prog import prog_name
31
33
 
32
- _GH_RERUN_HINT = "agex: rerun once network is reachable (gh failed)"
33
34
  _AGENT_HELP = "Backend: claude-code, codex, copilot, or acp."
34
35
 
35
36
 
37
+ def _gh_rerun_hint() -> str:
38
+ """``<prog>: rerun once network is reachable`` — phrased with the invoked name."""
39
+ return f"{prog_name()}: rerun once network is reachable (gh failed)"
40
+
41
+
36
42
  class _AgexArgumentParser(argparse.ArgumentParser):
37
43
  """ArgumentParser used everywhere via ``parser_class=``.
38
44
 
@@ -71,7 +77,7 @@ def _parse_backend_or_report(agent: Optional[str]):
71
77
  try:
72
78
  return parse_backend(agent), None
73
79
  except ValueError as exc:
74
- print(f"agex: error: {exc}", file=sys.stderr)
80
+ print(f"{prog_name()}: error: {exc}", file=sys.stderr)
75
81
  return None, 2
76
82
 
77
83
 
@@ -156,7 +162,7 @@ def _cmd_pr_lint(args: argparse.Namespace) -> int:
156
162
  agent=args.agent, project_dir=Path.cwd(), exit_on_violation=args.exit_on_violation
157
163
  )
158
164
  except ValueError as exc:
159
- print(f"agex: {exc}", file=sys.stderr)
165
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
160
166
  return 2
161
167
  _emit(stdout, stderr)
162
168
  return exit_code
@@ -173,11 +179,12 @@ def _cmd_pr_open(args: argparse.Namespace) -> int:
173
179
  delayed_read=args.delayed_read,
174
180
  )
175
181
  except ValueError as exc:
176
- print(f"agex: {exc}", file=sys.stderr)
182
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
177
183
  return 2
178
184
  except RuntimeError as exc:
185
+ prog = prog_name()
179
186
  print(str(exc), file=sys.stderr)
180
- print("agex: rerun 'agex pr open ...' once network is reachable", file=sys.stderr)
187
+ print(f"{prog}: rerun '{prog} pr open ...' once network is reachable", file=sys.stderr)
181
188
  return 1
182
189
  _emit(stdout, stderr)
183
190
  return exit_code
@@ -189,11 +196,11 @@ def _cmd_pr_reply(args: argparse.Namespace) -> int:
189
196
  agent=args.agent, project_dir=Path.cwd(), pr=args.pr
190
197
  )
191
198
  except ValueError as exc:
192
- print(f"agex: {exc}", file=sys.stderr)
199
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
193
200
  return 2
194
201
  except RuntimeError as exc:
195
202
  print(str(exc), file=sys.stderr)
196
- print(_GH_RERUN_HINT, file=sys.stderr)
203
+ print(_gh_rerun_hint(), file=sys.stderr)
197
204
  return 1
198
205
  _emit(stdout, stderr, stderr_newline=False)
199
206
  return exit_code
@@ -205,11 +212,11 @@ def _cmd_pr_read(args: argparse.Namespace) -> int:
205
212
  agent=args.agent, project_dir=Path.cwd(), pr=args.pr, wait=args.wait
206
213
  )
207
214
  except ValueError as exc:
208
- print(f"agex: {exc}", file=sys.stderr)
215
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
209
216
  return 2
210
217
  except RuntimeError as exc:
211
218
  print(str(exc), file=sys.stderr)
212
- print(_GH_RERUN_HINT, file=sys.stderr)
219
+ print(_gh_rerun_hint(), file=sys.stderr)
213
220
  return 1
214
221
  _emit(stdout, stderr)
215
222
  return exit_code
@@ -221,11 +228,27 @@ def _cmd_pr_await(args: argparse.Namespace) -> int:
221
228
  agent=args.agent, project_dir=Path.cwd(), pr=args.pr, max_wait=args.max_wait
222
229
  )
223
230
  except ValueError as exc:
224
- print(f"agex: {exc}", file=sys.stderr)
231
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
232
+ return 2
233
+ except RuntimeError as exc:
234
+ print(str(exc), file=sys.stderr)
235
+ print(_gh_rerun_hint(), file=sys.stderr)
236
+ return 1
237
+ _emit(stdout, stderr)
238
+ return exit_code
239
+
240
+
241
+ def _cmd_pr_review(args: argparse.Namespace) -> int:
242
+ try:
243
+ stdout, exit_code, stderr = pr_review_script.run(
244
+ agent=args.agent, project_dir=Path.cwd(), pr=args.pr
245
+ )
246
+ except ValueError as exc:
247
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
225
248
  return 2
226
249
  except RuntimeError as exc:
227
250
  print(str(exc), file=sys.stderr)
228
- print(_GH_RERUN_HINT, file=sys.stderr)
251
+ print(_gh_rerun_hint(), file=sys.stderr)
229
252
  return 1
230
253
  _emit(stdout, stderr)
231
254
  return exit_code
@@ -235,11 +258,11 @@ def _cmd_pr_delta(args: argparse.Namespace) -> int:
235
258
  try:
236
259
  stdout, exit_code, stderr = pr_delta_script.run(agent=args.agent, project_dir=Path.cwd())
237
260
  except ValueError as exc:
238
- print(f"agex: {exc}", file=sys.stderr)
261
+ print(f"{prog_name()}: {exc}", file=sys.stderr)
239
262
  return 2
240
263
  except RuntimeError as exc:
241
264
  print(str(exc), file=sys.stderr)
242
- print(_GH_RERUN_HINT, file=sys.stderr)
265
+ print(_gh_rerun_hint(), file=sys.stderr)
243
266
  return 1
244
267
  _emit(stdout, stderr, stderr_newline=False)
245
268
  return exit_code
@@ -270,7 +293,7 @@ def _group_help(parser: argparse.ArgumentParser):
270
293
 
271
294
  def _build_parser() -> argparse.ArgumentParser:
272
295
  parser = _AgexArgumentParser(
273
- prog="agex",
296
+ prog=prog_name(),
274
297
  description="Agent-operated developer-experience CLI.",
275
298
  )
276
299
  parser.add_argument("--version", action="version", version=__version__)
@@ -397,6 +420,14 @@ def _register_pr(sub: argparse._SubParsersAction) -> None:
397
420
  _add_agent_option(p_await, required=False, help_text=_AGENT_HELP)
398
421
  p_await.set_defaults(func=_cmd_pr_await)
399
422
 
423
+ p_review = pr_sub.add_parser(
424
+ "review",
425
+ help="Post the Qodo agentic-review trigger (/agentic_review) on a PR.",
426
+ )
427
+ p_review.add_argument("pr", type=int, nargs="?", default=None)
428
+ _add_agent_option(p_review, required=False, help_text=_AGENT_HELP)
429
+ p_review.set_defaults(func=_cmd_pr_review)
430
+
400
431
  p_delta = pr_sub.add_parser("delta", help="Show the delta since the last PR read.")
401
432
  _add_agent_option(p_delta, required=False, help_text=_AGENT_HELP)
402
433
  p_delta.set_defaults(func=_cmd_pr_delta)
@@ -441,7 +472,9 @@ def _main_entrypoint() -> None:
441
472
  """
442
473
  argv = sys.argv[1:]
443
474
  if argv and not argv[0].startswith("-") and argv[0] not in _KNOWN_COMMANDS:
444
- print(f"agex: error: unknown command '{argv[0]}'", file=sys.stderr)
475
+ print(f"{prog_name()}: error: unknown command '{argv[0]}'", file=sys.stderr)
476
+ # `agex` here is the explain-topic identifier (topics/agex.md), not the
477
+ # invoked command name — the canonical "what is this tool" page.
445
478
  stdout, _, _ = explain_script.run("agex")
446
479
  sys.stdout.write(stdout)
447
480
  sys.exit(2)
@@ -1,7 +1,7 @@
1
1
  {% set icon = {"ok": "✓", "warn": "⚠️", "fail": "✗", "info": "·"} -%}
2
- # agex doctor
2
+ # {{ prog }} doctor
3
3
 
4
- **agex:** `{{ version }}`
4
+ **{{ prog }}:** `{{ version }}`
5
5
  **Project:** `{{ project_dir }}`
6
6
 
7
7
  {% for cat in categories %}
@@ -24,6 +24,7 @@ from agent_experience.core.paths import (
24
24
  config_path,
25
25
  data_dir,
26
26
  )
27
+ from agent_experience.core.prog import error_prefix
27
28
  from agent_experience.core.render import render_string
28
29
  from agent_experience.core.skill_loader import load_skill
29
30
 
@@ -74,8 +75,8 @@ def _check_version() -> CheckResult:
74
75
  _NAME_AGEX_VERSION,
75
76
  "fail",
76
77
  "Could not resolve `agent_experience.__version__`. Reinstall with "
77
- "`uv pip install -e .[dev]`, `pipx install agex-cli`, or "
78
- "`pipx install agent-devex`.",
78
+ "`uv pip install -e .[dev]`, `pipx install agex-cli`, "
79
+ "`pipx install agent-devex`, or `pipx install devex-cli`.",
79
80
  )
80
81
  return CheckResult(_NAME_AGEX_VERSION, "ok", __version__)
81
82
 
@@ -341,24 +342,24 @@ def run(role: str | None = None) -> tuple[str, int, str]:
341
342
  Read-only. Never initializes ``.agex/``.
342
343
  """
343
344
  if role is not None and _ROLE_RE.match(role) is None:
344
- return ("", 2, f"agex: error: invalid role slug '{role}'")
345
+ return ("", 2, error_prefix(f"invalid role slug '{role}'"))
345
346
 
346
347
  role_section: str | None = None
347
348
  if role is not None:
348
349
  trav = _resolve_role(role)
349
350
  if trav is None:
350
- return ("", 2, f"agex: error: unknown role '{role}'")
351
+ return ("", 2, error_prefix(f"unknown role '{role}'"))
351
352
  try:
352
353
  role_text = trav.read_text(encoding="utf-8")
353
354
  except (OSError, UnicodeDecodeError) as exc:
354
- return ("", 1, f"agex: error: could not read role asset for '{role}': {exc}")
355
+ return ("", 1, error_prefix(f"could not read role asset for '{role}': {exc}"))
355
356
  # Role assets are Jinja templates per the addendum spec; v0.1 passes
356
357
  # an empty context but rendering still resolves any `{% raw %}` /
357
358
  # `{{ }}` markup the role file may use, rather than dumping it raw.
358
359
  try:
359
360
  role_section = render_string(role_text, {})
360
361
  except Exception as exc:
361
- return ("", 1, f"agex: error: failed to render role '{role}': {exc}")
362
+ return ("", 1, error_prefix(f"failed to render role '{role}': {exc}"))
362
363
 
363
364
  categories = _build_categories()
364
365
  summary = _summarize(categories)
@@ -369,8 +370,10 @@ def run(role: str | None = None) -> tuple[str, int, str]:
369
370
  return (
370
371
  "",
371
372
  1,
372
- f"agex: error: could not read `doctor/assets/report.md.j2`: {exc}. "
373
- "Reinstall the package.",
373
+ error_prefix(
374
+ f"could not read `doctor/assets/report.md.j2`: {exc}. "
375
+ "Reinstall the package."
376
+ ),
374
377
  )
375
378
  out = render_string(
376
379
  template_text,
@@ -386,6 +389,6 @@ def run(role: str | None = None) -> tuple[str, int, str]:
386
389
  )
387
390
 
388
391
  if summary["fail"] > 0:
389
- stderr = f"agex: error: {summary['fail']} health check(s) failed"
392
+ stderr = error_prefix(f"{summary['fail']} health check(s) failed")
390
393
  return (out, 1, stderr)
391
394
  return (out, 0, "")
@@ -34,4 +34,4 @@ agex overview --agent claude-code # what's in this project?
34
34
 
35
35
  ## Repo
36
36
 
37
- <https://github.com/agentculture/agex-cli>
37
+ <https://github.com/agentculture/devex>
@@ -2,6 +2,7 @@ import re
2
2
  from importlib.resources import files
3
3
  from importlib.resources.abc import Traversable
4
4
 
5
+ from agent_experience.core.prog import error_prefix
5
6
  from agent_experience.core.skill_loader import Skill, load_skill
6
7
 
7
8
  _TOPIC_RE = re.compile(r"^[a-z][a-z0-9-]*$")
@@ -54,7 +55,7 @@ def run(topic: str) -> tuple[str, int, str]:
54
55
  if resolved is None:
55
56
  agex_page = _commands_root().joinpath("explain", "assets", "topics", "agex.md")
56
57
  body = agex_page.read_text(encoding="utf-8") if agex_page.is_file() else ""
57
- return (body, 2, f"agex: error: unknown topic '{topic}'")
58
+ return (body, 2, error_prefix(f"unknown topic '{topic}'"))
58
59
 
59
60
  kind, trav = resolved
60
61
  if kind == "concept":
@@ -8,6 +8,7 @@ from agent_experience.core.backend import Backend
8
8
  from agent_experience.core.config import load as load_config
9
9
  from agent_experience.core.config import save as save_config
10
10
  from agent_experience.core.paths import ensure_init
11
+ from agent_experience.core.prog import error_prefix, prog_name
11
12
 
12
13
 
13
14
  def _fragments_file() -> Traversable:
@@ -110,7 +111,7 @@ def install(backend: Backend) -> tuple[str, int, str]:
110
111
  try:
111
112
  hooks = _load_hooks_file(hooks_file)
112
113
  except ValueError as e:
113
- return ("", 2, f"agex: error: {e}")
114
+ return ("", 2, error_prefix(str(e)))
114
115
 
115
116
  written_ids, added_count = _merge_fragments(hooks, fragments)
116
117
  if added_count:
@@ -142,7 +143,8 @@ def install(backend: Backend) -> tuple[str, int, str]:
142
143
  status_line,
143
144
  "- Fragment IDs: " + ", ".join(f"`{i}`" for i in written_ids),
144
145
  "",
145
- f"Next: run `agex learn gamify --agent {backend.value}` to set up the levelup skill.",
146
+ f"Next: run `{prog_name()} learn gamify --agent {backend.value}`"
147
+ " to set up the levelup skill.",
146
148
  "",
147
149
  ]
148
150
  return ("\n".join(lines), 0, "")
@@ -176,7 +178,7 @@ def uninstall(backend: Backend) -> tuple[str, int, str]:
176
178
  try:
177
179
  hooks = _load_hooks_file(hooks_file)
178
180
  except ValueError as e:
179
- return ("", 2, f"agex: error: {e}")
181
+ return ("", 2, error_prefix(str(e)))
180
182
 
181
183
  removed_count = _remove_ids_from_hooks(hooks, ids_to_remove)
182
184
  if removed_count:
@@ -196,6 +198,6 @@ def _unsupported_notice(backend: Backend) -> str:
196
198
  return (
197
199
  f"## `gamify` is not supported on {backend.value}\n\n"
198
200
  f"Hooks are required to track usage events, and {backend.value} does not expose "
199
- f"a hook interface agex can write to.\n\n"
200
- "Want this supported? Open an issue: <https://github.com/agentculture/agex-cli/issues>\n"
201
+ f"a hook interface {prog_name()} can write to.\n\n"
202
+ "Want this supported? Open an issue: <https://github.com/agentculture/devex/issues>\n"
201
203
  )
@@ -2,6 +2,7 @@ from datetime import datetime, timezone
2
2
 
3
3
  from agent_experience.core.hook_io import append_event
4
4
  from agent_experience.core.paths import ensure_init
5
+ from agent_experience.core.prog import error_prefix
5
6
 
6
7
 
7
8
  def run(event: str, args: list[str]) -> tuple[str, int, str]:
@@ -20,5 +21,5 @@ def run(event: str, args: list[str]) -> tuple[str, int, str]:
20
21
  except ValueError as e:
21
22
  # append_event → _stream_path rejects names that don't match the
22
23
  # `^[a-z][a-z0-9-]*$` slug whitelist (path-traversal guard).
23
- return ("", 2, f"agex: error: {e}")
24
+ return ("", 2, error_prefix(str(e)))
24
25
  return ("", 0, "")
@@ -1,6 +1,6 @@
1
1
  # Lessons — {{ backend }}
2
2
 
3
- Run `agex learn <topic> --agent {{ backend }}` to learn one.
3
+ Run `{{ prog }} learn <topic> --agent {{ backend }}` to learn one.
4
4
 
5
5
  {% for topic in topics -%}
6
6
  - **`{{ topic.name }}`** — {{ topic.description }}{% if topic.unsupported %} _(unsupported on {{ backend }}: {{ topic.unsupported }})_{% endif %}
@@ -3,6 +3,7 @@ from importlib.resources import as_file, files
3
3
  from importlib.resources.abc import Traversable
4
4
 
5
5
  from agent_experience.core.backend import Backend
6
+ from agent_experience.core.prog import error_prefix
6
7
  from agent_experience.core.render import render_string
7
8
  from agent_experience.core.skill_loader import Skill, load_skill
8
9
 
@@ -54,13 +55,13 @@ def run_topic(topic: str, backend: Backend) -> tuple[str, int, str]:
54
55
  """Return (stdout, exit_code, stderr) for a specific lesson topic."""
55
56
  if not _TOPIC_RE.match(topic):
56
57
  menu_out, _, _ = run_menu(backend)
57
- return (menu_out, 2, f"agex: error: unknown topic '{topic}'")
58
+ return (menu_out, 2, error_prefix(f"unknown topic '{topic}'"))
58
59
 
59
60
  topic_dir = _learn_assets().joinpath("topics", topic)
60
61
  skill_md = topic_dir.joinpath(_SKILL_FILENAME)
61
62
  if not skill_md.is_file():
62
63
  menu_out, _, _ = run_menu(backend)
63
- return (menu_out, 2, f"agex: error: unknown topic '{topic}'")
64
+ return (menu_out, 2, error_prefix(f"unknown topic '{topic}'"))
64
65
 
65
66
  skill = _load_skill_from_traversable(skill_md)
66
67
  template_path = topic_dir.joinpath("assets", "skill-template", backend.value, _SKILL_FILENAME)