codexloop 0.2.0__tar.gz → 0.3.1__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 (307) hide show
  1. codexloop-0.3.1/.agent/rules/codexloop-architecture.md +29 -0
  2. codexloop-0.3.1/.agent/rules/codexloop-completion.md +42 -0
  3. codexloop-0.3.1/.agent/rules/codexloop-docs.md +50 -0
  4. codexloop-0.3.1/.agent/rules/codexloop-quota-and-capacity.md +44 -0
  5. codexloop-0.3.1/.agent/rules/codexloop-releasing.md +51 -0
  6. codexloop-0.3.1/.agent/rules/codexloop-rest-surface.md +40 -0
  7. codexloop-0.2.0/.cursor/rules/codexloop-run.mdc → codexloop-0.3.1/.agent/rules/codexloop-run.md +2 -5
  8. codexloop-0.3.1/.agent/rules/codexloop-testing.md +34 -0
  9. codexloop-0.3.1/.agents/skills/codexloop-architecture/SKILL.md +32 -0
  10. codexloop-0.3.1/.agents/skills/codexloop-completion/SKILL.md +45 -0
  11. codexloop-0.3.1/.agents/skills/codexloop-docs/SKILL.md +53 -0
  12. codexloop-0.3.1/.agents/skills/codexloop-quota-and-capacity/SKILL.md +47 -0
  13. codexloop-0.3.1/.agents/skills/codexloop-releasing/SKILL.md +54 -0
  14. codexloop-0.3.1/.agents/skills/codexloop-rest-surface/SKILL.md +43 -0
  15. codexloop-0.3.1/.agents/skills/codexloop-testing/SKILL.md +37 -0
  16. codexloop-0.3.1/.claude/skills/codexloop-architecture/SKILL.md +32 -0
  17. codexloop-0.3.1/.claude/skills/codexloop-completion/SKILL.md +45 -0
  18. codexloop-0.3.1/.claude/skills/codexloop-docs/SKILL.md +53 -0
  19. codexloop-0.3.1/.claude/skills/codexloop-quota-and-capacity/SKILL.md +47 -0
  20. codexloop-0.3.1/.claude/skills/codexloop-releasing/SKILL.md +54 -0
  21. codexloop-0.3.1/.claude/skills/codexloop-rest-surface/SKILL.md +43 -0
  22. codexloop-0.3.1/.claude/skills/codexloop-testing/SKILL.md +37 -0
  23. codexloop-0.3.1/.cursor/rules/codexloop-architecture.mdc +33 -0
  24. codexloop-0.3.1/.cursor/rules/codexloop-completion.mdc +46 -0
  25. codexloop-0.3.1/.cursor/rules/codexloop-docs.mdc +54 -0
  26. codexloop-0.3.1/.cursor/rules/codexloop-quota-and-capacity.mdc +48 -0
  27. codexloop-0.3.1/.cursor/rules/codexloop-releasing.mdc +55 -0
  28. codexloop-0.3.1/.cursor/rules/codexloop-rest-surface.mdc +44 -0
  29. codexloop-0.3.1/.cursor/rules/codexloop-run.mdc +14 -0
  30. codexloop-0.3.1/.cursor/rules/codexloop-testing.mdc +38 -0
  31. codexloop-0.3.1/.github/ISSUE_TEMPLATE/bug_report.yml +82 -0
  32. codexloop-0.3.1/.github/ISSUE_TEMPLATE/config.yml +11 -0
  33. codexloop-0.3.1/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
  34. codexloop-0.3.1/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  35. {codexloop-0.2.0 → codexloop-0.3.1}/.github/workflows/ci.yml +24 -1
  36. {codexloop-0.2.0 → codexloop-0.3.1}/.github/workflows/release-please.yml +5 -1
  37. {codexloop-0.2.0 → codexloop-0.3.1}/.gitignore +1 -0
  38. codexloop-0.3.1/.release-please-manifest.json +3 -0
  39. codexloop-0.3.1/AGENTS.md +63 -0
  40. {codexloop-0.2.0 → codexloop-0.3.1}/CHANGELOG.md +43 -0
  41. codexloop-0.3.1/CLAUDE.md +63 -0
  42. codexloop-0.3.1/CODE_OF_CONDUCT.md +137 -0
  43. codexloop-0.3.1/CONTRIBUTING.md +170 -0
  44. codexloop-0.3.1/GEMINI.md +42 -0
  45. codexloop-0.3.1/PKG-INFO +246 -0
  46. codexloop-0.3.1/README.md +195 -0
  47. codexloop-0.3.1/SECURITY.md +88 -0
  48. codexloop-0.3.1/SUPPORT.md +18 -0
  49. {codexloop-0.2.0 → codexloop-0.3.1}/docs/getting-started.md +7 -2
  50. {codexloop-0.2.0 → codexloop-0.3.1}/docs/index.md +1 -1
  51. {codexloop-0.2.0 → codexloop-0.3.1}/docs/plans/architecture-and-roadmap.md +6 -6
  52. {codexloop-0.2.0 → codexloop-0.3.1}/pyproject.toml +14 -1
  53. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/__init__.py +1 -1
  54. codexloop-0.3.1/src/codexloop/application/interfaces/__init__.py +75 -0
  55. codexloop-0.3.1/src/codexloop/application/interfaces/agent.py +46 -0
  56. codexloop-0.3.1/src/codexloop/application/interfaces/api.py +10 -0
  57. codexloop-0.3.1/src/codexloop/application/interfaces/control.py +21 -0
  58. {codexloop-0.2.0/src/codexloop/application/usecases → codexloop-0.3.1/src/codexloop/application/interfaces}/doctor.py +7 -9
  59. codexloop-0.3.1/src/codexloop/application/interfaces/observability.py +42 -0
  60. codexloop-0.3.1/src/codexloop/application/interfaces/permissions.py +14 -0
  61. codexloop-0.3.1/src/codexloop/application/interfaces/storage.py +31 -0
  62. codexloop-0.3.1/src/codexloop/application/interfaces/system.py +16 -0
  63. codexloop-0.3.1/src/codexloop/application/ports.py +61 -0
  64. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/runner.py +157 -3
  65. codexloop-0.3.1/src/codexloop/application/usecases/doctor.py +18 -0
  66. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/run_control.py +1 -5
  67. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/bootstrap.py +43 -7
  68. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/app.py +26 -1
  69. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/asyncio.py +2 -0
  70. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/run.py +10 -1
  71. codexloop-0.3.1/src/codexloop/cli/commands/wind_down_cmd.py +34 -0
  72. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/control.py +46 -1
  73. codexloop-0.3.1/src/codexloop/domain/forecast.py +271 -0
  74. codexloop-0.3.1/src/codexloop/domain/handoff_marker.py +107 -0
  75. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/loop.py +31 -2
  76. codexloop-0.3.1/src/codexloop/domain/verbosity.py +80 -0
  77. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/gateway.py +141 -2
  78. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/logging.py +21 -0
  79. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/rundir.py +47 -2
  80. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/fakes.py +3 -0
  81. codexloop-0.3.1/tests/application/test_interfaces_convention.py +100 -0
  82. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/test_runner.py +66 -0
  83. codexloop-0.3.1/tests/application/test_runner_wind_down_coverage.py +266 -0
  84. codexloop-0.3.1/tests/application/test_sleep_interruptible.py +131 -0
  85. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/test_waiting_runner.py +6 -3
  86. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/test_app.py +12 -0
  87. codexloop-0.3.1/tests/cli/test_sysexit.py +30 -0
  88. codexloop-0.3.1/tests/cli/test_verbosity_flags.py +48 -0
  89. codexloop-0.3.1/tests/cli/test_wind_down_cmd.py +71 -0
  90. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_control.py +77 -0
  91. codexloop-0.3.1/tests/domain/test_forecast.py +209 -0
  92. codexloop-0.3.1/tests/domain/test_handoff_marker.py +83 -0
  93. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_loop.py +73 -1
  94. codexloop-0.3.1/tests/domain/test_verbosity.py +60 -0
  95. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_providers_gateway_extra.py +2 -1
  96. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_appserver_gateway.py +9 -0
  97. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_control_and_savepoints.py +15 -1
  98. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_coverage_boost.py +5 -1
  99. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_doctor_env.py +36 -0
  100. codexloop-0.3.1/tests/infrastructure/test_event_to_dict.py +288 -0
  101. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_gateway.py +110 -0
  102. codexloop-0.3.1/tests/infrastructure/test_git_savepoints_units.py +69 -0
  103. codexloop-0.3.1/tests/infrastructure/test_handoff_marker.py +137 -0
  104. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_logging_redact.py +41 -0
  105. codexloop-0.3.1/tests/infrastructure/test_rollout_scan.py +91 -0
  106. codexloop-0.3.1/tests/infrastructure/test_rundir_run_id.py +48 -0
  107. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/system/test_subprocess_smoke.py +51 -0
  108. codexloop-0.3.1/uv.lock +2277 -0
  109. codexloop-0.2.0/.release-please-manifest.json +0 -3
  110. codexloop-0.2.0/AGENTS.md +0 -10
  111. codexloop-0.2.0/CLAUDE.md +0 -5
  112. codexloop-0.2.0/CODE_OF_CONDUCT.md +0 -4
  113. codexloop-0.2.0/CONTRIBUTING.md +0 -29
  114. codexloop-0.2.0/PKG-INFO +0 -112
  115. codexloop-0.2.0/README.md +0 -61
  116. codexloop-0.2.0/SECURITY.md +0 -13
  117. codexloop-0.2.0/src/codexloop/application/ports.py +0 -158
  118. {codexloop-0.2.0 → codexloop-0.3.1}/.agents/skills/codexloop-run/SKILL.md +0 -0
  119. {codexloop-0.2.0 → codexloop-0.3.1}/.claude/skills/codexloop-run/SKILL.md +0 -0
  120. {codexloop-0.2.0 → codexloop-0.3.1}/.editorconfig +0 -0
  121. {codexloop-0.2.0 → codexloop-0.3.1}/.github/CODEOWNERS +0 -0
  122. {codexloop-0.2.0 → codexloop-0.3.1}/.github/workflows/docs.yml +0 -0
  123. {codexloop-0.2.0 → codexloop-0.3.1}/.github/workflows/publish-testpypi.yml +0 -0
  124. {codexloop-0.2.0 → codexloop-0.3.1}/.pre-commit-config.yaml +0 -0
  125. {codexloop-0.2.0 → codexloop-0.3.1}/LICENSE +0 -0
  126. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0001-onion-import-linter.md +0 -0
  127. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0002-subprocess-codex-exec.md +0 -0
  128. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0003-credits-exhausted.md +0 -0
  129. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0004-adaptive-probe-loop.md +0 -0
  130. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0005-layered-capacity-probe.md +0 -0
  131. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0006-generated-openai-rest.md +0 -0
  132. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0007-default-approval-sandbox.md +0 -0
  133. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0008-policy-via-c-flags.md +0 -0
  134. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0009-optional-app-server.md +0 -0
  135. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0010-rollout-best-effort.md +0 -0
  136. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0011-never-consume-resets.md +0 -0
  137. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/0012-minimum-codex-version.md +0 -0
  138. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/adr/index.md +0 -0
  139. {codexloop-0.2.0 → codexloop-0.3.1}/docs/architecture/index.md +0 -0
  140. {codexloop-0.2.0 → codexloop-0.3.1}/docs/contributing.md +0 -0
  141. {codexloop-0.2.0 → codexloop-0.3.1}/docs/guides/rest-api-surface.md +0 -0
  142. {codexloop-0.2.0 → codexloop-0.3.1}/docs/plans/_shared-transplant-outline.md +0 -0
  143. {codexloop-0.2.0 → codexloop-0.3.1}/docs/plans/research-notes.md +0 -0
  144. {codexloop-0.2.0 → codexloop-0.3.1}/docs/publishing.md +0 -0
  145. {codexloop-0.2.0 → codexloop-0.3.1}/docs/reference/cli.md +0 -0
  146. {codexloop-0.2.0 → codexloop-0.3.1}/docs/superpowers/plans/2026-08-13-codexloop-implementation.md +0 -0
  147. {codexloop-0.2.0 → codexloop-0.3.1}/mkdocs.yml +0 -0
  148. {codexloop-0.2.0 → codexloop-0.3.1}/release-please-config.json +0 -0
  149. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/__init__.py +0 -0
  150. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/dto.py +0 -0
  151. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/__init__.py +0 -0
  152. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/list_threads.py +0 -0
  153. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/preflight.py +0 -0
  154. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/resume_thread.py +0 -0
  155. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/application/usecases/run_plan.py +0 -0
  156. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/__init__.py +0 -0
  157. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/__init__.py +0 -0
  158. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/approval_cmd.py +0 -0
  159. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/capacity.py +0 -0
  160. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/cwd_cmd.py +0 -0
  161. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/doctor.py +0 -0
  162. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/effort_cmd.py +0 -0
  163. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/logs.py +0 -0
  164. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/model_cmd.py +0 -0
  165. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/prompt.py +0 -0
  166. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/reset.py +0 -0
  167. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/resume.py +0 -0
  168. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/runs.py +0 -0
  169. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/sandbox_cmd.py +0 -0
  170. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/savepoints.py +0 -0
  171. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/snapshot.py +0 -0
  172. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/status.py +0 -0
  173. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/stop.py +0 -0
  174. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/threads.py +0 -0
  175. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/unwind.py +0 -0
  176. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/commands/watch.py +0 -0
  177. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/cli/render.py +0 -0
  178. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/__init__.py +0 -0
  179. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/approval.py +0 -0
  180. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/backoff.py +0 -0
  181. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/budget.py +0 -0
  182. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/capacity.py +0 -0
  183. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/classify.py +0 -0
  184. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/completion.py +0 -0
  185. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/error_codes.py +0 -0
  186. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/errors.py +0 -0
  187. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/model_profile.py +0 -0
  188. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/plan.py +0 -0
  189. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/savepoint.py +0 -0
  190. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/savepoint_message.py +0 -0
  191. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/session.py +0 -0
  192. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/signals.py +0 -0
  193. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/domain/waiting.py +0 -0
  194. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/__init__.py +0 -0
  195. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/__init__.py +0 -0
  196. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/argv.py +0 -0
  197. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/events.py +0 -0
  198. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/probe.py +0 -0
  199. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/process.py +0 -0
  200. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/schema.py +0 -0
  201. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/scripted.py +0 -0
  202. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/agent/translate.py +0 -0
  203. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/__init__.py +0 -0
  204. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/api_baseline.json +0 -0
  205. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/binder.py +0 -0
  206. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/gateway.py +0 -0
  207. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/introspect.py +0 -0
  208. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/json_io.py +0 -0
  209. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/params.py +0 -0
  210. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/providers.py +0 -0
  211. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/api/registry.py +0 -0
  212. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/appserver/__init__.py +0 -0
  213. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/appserver/client.py +0 -0
  214. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/appserver/gateway.py +0 -0
  215. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/appserver/ratelimits.py +0 -0
  216. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/audit.py +0 -0
  217. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/capacity_probe.py +0 -0
  218. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/clock.py +0 -0
  219. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/config.py +0 -0
  220. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/control.py +0 -0
  221. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/doctor_env.py +0 -0
  222. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/events.py +0 -0
  223. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/git_savepoints.py +0 -0
  224. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/lock.py +0 -0
  225. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/notify.py +0 -0
  226. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/progress.py +0 -0
  227. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/redact.py +0 -0
  228. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/rollout.py +0 -0
  229. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/snapshot.py +0 -0
  230. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/state.py +0 -0
  231. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/state_bus.py +0 -0
  232. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/infrastructure/stream_ui.py +0 -0
  233. {codexloop-0.2.0 → codexloop-0.3.1}/src/codexloop/py.typed +0 -0
  234. {codexloop-0.2.0 → codexloop-0.3.1}/tests/__init__.py +0 -0
  235. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/__init__.py +0 -0
  236. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/test_doctor.py +0 -0
  237. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/test_ports.py +0 -0
  238. {codexloop-0.2.0 → codexloop-0.3.1}/tests/application/test_usecases.py +0 -0
  239. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/__init__.py +0 -0
  240. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/test_api.py +0 -0
  241. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/test_asyncio.py +0 -0
  242. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/test_e2e_shim.py +0 -0
  243. {codexloop-0.2.0 → codexloop-0.3.1}/tests/cli/test_ops_commands.py +0 -0
  244. {codexloop-0.2.0 → codexloop-0.3.1}/tests/conftest.py +0 -0
  245. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/__init__.py +0 -0
  246. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/strategies.py +0 -0
  247. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_approval.py +0 -0
  248. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_backoff.py +0 -0
  249. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_budget.py +0 -0
  250. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_capacity.py +0 -0
  251. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_classify.py +0 -0
  252. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_completion.py +0 -0
  253. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_error_codes.py +0 -0
  254. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_model_profile.py +0 -0
  255. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_plan.py +0 -0
  256. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_savepoint.py +0 -0
  257. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_session.py +0 -0
  258. {codexloop-0.2.0 → codexloop-0.3.1}/tests/domain/test_waiting.py +0 -0
  259. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/README.md +0 -0
  260. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/clean_completion.jsonl +0 -0
  261. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/done_with_marker.jsonl +0 -0
  262. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/huge_line.jsonl +0 -0
  263. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/malformed_line.jsonl +0 -0
  264. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/tool_heavy.jsonl +0 -0
  265. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/truncated_stream.jsonl +0 -0
  266. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/turn_failed_429_quota.jsonl +0 -0
  267. {codexloop-0.2.0 → codexloop-0.3.1}/tests/fixtures/jsonl/turn_failed_429_window.jsonl +0 -0
  268. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/__init__.py +0 -0
  269. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/__init__.py +0 -0
  270. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_binder.py +0 -0
  271. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_drift.py +0 -0
  272. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_gateway.py +0 -0
  273. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_introspect.py +0 -0
  274. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_json_io.py +0 -0
  275. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_params.py +0 -0
  276. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_params_extra.py +0 -0
  277. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/api/test_providers.py +0 -0
  278. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_appserver.py +0 -0
  279. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_argv.py +0 -0
  280. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_capacity_probe.py +0 -0
  281. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_config.py +0 -0
  282. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_events.py +0 -0
  283. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_lock.py +0 -0
  284. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_probe.py +0 -0
  285. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_process.py +0 -0
  286. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_ratelimits_extra.py +0 -0
  287. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_rollout.py +0 -0
  288. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_rundir_state.py +0 -0
  289. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_scripted.py +0 -0
  290. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_snapshot.py +0 -0
  291. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_state_bus.py +0 -0
  292. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_stream_ui.py +0 -0
  293. {codexloop-0.2.0 → codexloop-0.3.1}/tests/infrastructure/test_translate.py +0 -0
  294. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/fixtures/agent_scripts/done.json +0 -0
  295. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/fixtures/agent_scripts/quota_then_topup.json +0 -0
  296. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/fixtures/agent_scripts/unknown_429.json +0 -0
  297. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/fixtures/agent_scripts/wait_long.json +0 -0
  298. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/fixtures/agent_scripts/window_then_done.json +0 -0
  299. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/system/conftest.py +0 -0
  300. {codexloop-0.2.0 → codexloop-0.3.1}/tests/live/system/test_matrix_inprocess.py +0 -0
  301. {codexloop-0.2.0 → codexloop-0.3.1}/tests/shim/__init__.py +0 -0
  302. {codexloop-0.2.0 → codexloop-0.3.1}/tests/shim/fake_appserver.py +0 -0
  303. {codexloop-0.2.0 → codexloop-0.3.1}/tests/shim/fake_codex.py +0 -0
  304. {codexloop-0.2.0 → codexloop-0.3.1}/tests/shim/test_fake_codex.py +0 -0
  305. {codexloop-0.2.0 → codexloop-0.3.1}/tests/test_bootstrap.py +0 -0
  306. {codexloop-0.2.0 → codexloop-0.3.1}/tests/test_no_vendor_leak.py +0 -0
  307. {codexloop-0.2.0 → codexloop-0.3.1}/tests/test_packaging.py +0 -0
@@ -0,0 +1,29 @@
1
+ # codexloop-architecture (Antigravity mirror of `.claude/skills/codexloop-architecture/SKILL.md`)
2
+
3
+
4
+ # codexloop architecture
5
+
6
+ Dependencies point inward. `import-linter` enforces this in CI.
7
+
8
+ ```
9
+ src/codexloop/
10
+ ├── domain/ # PURE. stdlib only. No I/O, no async, no third-party.
11
+ ├── application/ # Protocol ports + use cases. Imports domain + stdlib.
12
+ ├── infrastructure/ # Adapters. ONLY layer that may import openai.
13
+ ├── cli/ # Typer. Calls application via bootstrap.
14
+ └── bootstrap.py # Composition root — the ONE module that sees every layer.
15
+ ```
16
+
17
+ ## Where does new code go?
18
+
19
+ 1. Touches FS, network, clock, or an SDK? → `infrastructure/`, behind a
20
+ `Protocol` in `application/interfaces/`. Never `import openai`
21
+ elsewhere.
22
+ 2. Pure decision, zero I/O? → `domain/`. Examples: `classify.py`,
23
+ `waiting.py`, `completion.py`, `capacity.py`.
24
+ 3. Orchestration (port → domain → port)? → `application/`.
25
+ 4. Argument parsing / terminal formatting? → `cli/`.
26
+
27
+ When in doubt, push logic inward. `lint-imports` names the broken contract.
28
+
29
+ See ADR 0001.
@@ -0,0 +1,42 @@
1
+ # codexloop-completion (Antigravity mirror of `.claude/skills/codexloop-completion/SKILL.md`)
2
+
3
+
4
+ # codexloop completion detection
5
+
6
+ `CompletionEvaluator` in `domain/completion.py` maps `TurnSignals` +
7
+ `CapacityState` into a `CompletionVerdict`.
8
+
9
+ ## CompletionVerdict variants
10
+
11
+ ```python
12
+ Done # task fully complete
13
+ Continue # remaining: list[str]
14
+ Blocked # reason: str — human intervention needed
15
+ ```
16
+
17
+ ## Three-layer evaluation
18
+
19
+ **Capacity rejection always outranks a completion claim.** If the turn is
20
+ not `Available`, return `Continue` regardless of structured output or
21
+ markers.
22
+
23
+ For an `Available` turn, the layers are:
24
+
25
+ 1. **Structured output** (`StructuredOutput` tool call result):
26
+ - `blocked_on` set → `Blocked(reason=blocked_on)`.
27
+ - `complete: true` and `remaining_work: []` → `Done`.
28
+ - `complete: true` but `remaining_work` not empty → `Continue`.
29
+ - `complete: false` → `Continue(remaining=remaining_work)`.
30
+
31
+ 2. **Marker on own line**: if `CODEXLOOP_TASK_FULLY_COMPLETE` appears on
32
+ its own line in the final message → `Done`.
33
+
34
+ 3. **Fallback**: `Continue(remaining=[])`.
35
+
36
+ The marker check uses `_marker_on_own_line(message, done_marker)`: the
37
+ string must be the only non-whitespace on the line. Partial matches or
38
+ inline occurrences do not count.
39
+
40
+ **Never treat a non-`Available` turn as `Done`.** Rate-limit windows and
41
+ transient errors are waitable; completion is deferred until capacity
42
+ returns.
@@ -0,0 +1,50 @@
1
+ # codexloop-docs (Antigravity mirror of `.claude/skills/codexloop-docs/SKILL.md`)
2
+
3
+
4
+ # codexloop docs
5
+
6
+ User-facing documentation lives in `docs/` and is built with
7
+ mkdocs-material.
8
+
9
+ ## Structure
10
+
11
+ ```
12
+ docs/
13
+ ├── index.md # landing page
14
+ ├── getting-started.md
15
+ ├── guides/ # how-to guides
16
+ │ └── rest-api-surface.md
17
+ ├── architecture/
18
+ │ ├── index.md
19
+ │ └── adr/ # Architecture Decision Records
20
+ │ ├── index.md
21
+ │ ├── 0001-onion-import-linter.md
22
+ │ └── 0002-subprocess-codex-exec.md
23
+ ├── contributing.md
24
+ └── publishing.md
25
+ ```
26
+
27
+ ## Commands
28
+
29
+ ```bash
30
+ mkdocs serve # live preview at http://127.0.0.1:8000
31
+ mkdocs build --strict # fail on warnings
32
+ ```
33
+
34
+ `--strict` runs in CI via `.github/workflows/docs.yml`.
35
+
36
+ ## ADRs
37
+
38
+ Architecture Decision Records follow the Nygard format. Each ADR gets a
39
+ number (0001, 0002, ...) and a kebab-case title. Add new ADRs to
40
+ `docs/architecture/adr/index.md`.
41
+
42
+ ## Excluded paths
43
+
44
+ `mkdocs.yml` excludes `plans/**` and `superpowers/**` from the built
45
+ site. These are workspace-specific and not user-facing.
46
+
47
+ ## Before pushing doc changes
48
+
49
+ Run `mkdocs build --strict` to catch broken links, missing pages, and
50
+ markdown errors.
@@ -0,0 +1,44 @@
1
+ # codexloop-quota-and-capacity (Antigravity mirror of `.claude/skills/codexloop-quota-and-capacity/SKILL.md`)
2
+
3
+
4
+ # codexloop quota and capacity
5
+
6
+ `QuotaExhausted` is a billing wall with no `resets_at` — it is **never
7
+ waitable** and always needs a human to top up. Rate-limit windows *are*
8
+ waitable.
9
+
10
+ ## CapacityState variants
11
+
12
+ ```python
13
+ Available # green light
14
+ ThrottleExhausted # retry_after: timedelta | None
15
+ WindowExhausted # resets_at: datetime | None, window: str
16
+ QuotaExhausted # reason: str — TERMINAL, never waitable
17
+ AuthFailed # reason: str — TERMINAL
18
+ TransientBackendError # retry_after: timedelta | None
19
+ ```
20
+
21
+ `is_waitable(state)` returns `False` only for `QuotaExhausted` and
22
+ `AuthFailed`.
23
+
24
+ ## Body-first classification
25
+
26
+ `classify(signals)` in `domain/classify.py` maps `TurnSignals` to a
27
+ `CapacityState` using this ladder:
28
+
29
+ 1. **Body wins.** `error.code` / `error.type` outrank HTTP status.
30
+ 2. Auth: `error.code` / `error.type` in `ErrorClass.AUTH`, or status 401
31
+ → `AuthFailed`.
32
+ 3. Quota: `error.code` / `error.type` in `ErrorClass.QUOTA` →
33
+ `QuotaExhausted` (terminal).
34
+ 4. Window: `ErrorClass.WINDOW` → `WindowExhausted` with `resets_at` from
35
+ plan windows.
36
+ 5. Throttle: `ErrorClass.THROTTLE` → `ThrottleExhausted` with
37
+ `retry_after`.
38
+ 6. Transient: `ErrorClass.TRANSIENT` or status 5xx →
39
+ `TransientBackendError`.
40
+ 7. Status 429 with no body marker → `WindowExhausted(resets_at=None)`.
41
+ 8. Fallback: `Available`.
42
+
43
+ High `used_percent` never outranks a billing marker. Completion claims
44
+ never outrank capacity rejection.
@@ -0,0 +1,51 @@
1
+ # codexloop-releasing (Antigravity mirror of `.claude/skills/codexloop-releasing/SKILL.md`)
2
+
3
+
4
+ # codexloop releasing
5
+
6
+ ## Gitflow
7
+
8
+ ```
9
+ develop (default branch) → main (releases)
10
+ ```
11
+
12
+ 1. Feature PRs squash into `develop`.
13
+ 2. `develop` merge-commits into `main` when ready to release.
14
+ 3. release-please opens a PR on `main` when it detects conventional
15
+ commits since the last tag.
16
+ 4. Merging the release PR publishes to PyPI.
17
+
18
+ ## Workflows
19
+
20
+ - **`ci.yml`**: runs on every push. Tests, linting, type checks, per-layer
21
+ coverage, import-linter, bandit, pip-audit.
22
+ - **`publish-testpypi.yml`**: publishes to TestPyPI on every `develop`
23
+ push. **Known gap: no test gate.** This workflow builds and publishes
24
+ without running tests first. It trusts that CI passed.
25
+ - **`release-please.yml`**: opens a release PR on `main` when conventional
26
+ commits land. Merging that PR publishes to PyPI (via GitHub Actions +
27
+ PyPI trusted publishing).
28
+
29
+ ## release-please
30
+
31
+ Configured in `release-please-config.json`:
32
+
33
+ ```json
34
+ {
35
+ "packages": {
36
+ ".": {
37
+ "release-type": "python",
38
+ "package-name": "codexloop",
39
+ "changelog-path": "CHANGELOG.md"
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ It maintains `CHANGELOG.md` automatically from conventional commits.
46
+
47
+ ## Before merging develop → main
48
+
49
+ 1. All CI gates green on `develop`.
50
+ 2. TestPyPI publish succeeded (workflow run shows no errors).
51
+ 3. CHANGELOG.md reflects all user-facing changes since last release.
@@ -0,0 +1,40 @@
1
+ # codexloop-rest-surface (Antigravity mirror of `.claude/skills/codexloop-rest-surface/SKILL.md`)
2
+
3
+
4
+ # codexloop REST surface
5
+
6
+ `codexloop api` generates a 1:1 CLI mirror of the OpenAI Python SDK's REST
7
+ methods. The tree is code-generated from the SDK itself, not maintained by
8
+ hand.
9
+
10
+ ## api_baseline.json drift gate
11
+
12
+ `api_baseline.json` freezes the **OpenAI SDK's** method count and list,
13
+ not codexloop's. It is a snapshot of what the SDK exposes, not what
14
+ codexloop adds.
15
+
16
+ A test fails when:
17
+
18
+ - The SDK adds or removes methods (changes `method_count`).
19
+ - Methods appear or disappear from the `methods` list.
20
+ - `local_helpers` (like `chat.completions.stream`) change.
21
+
22
+ This gate prevents SDK upgrades from silently altering the API surface
23
+ without review.
24
+
25
+ ## Refreshing the baseline
26
+
27
+ After an intentional SDK upgrade, refresh the baseline:
28
+
29
+ ```bash
30
+ codexloop api --help # generates the tree
31
+ # The test writes the new baseline to api_baseline.json
32
+ pytest tests/cli/test_api.py --update-baseline
33
+ ```
34
+
35
+ Commit the updated `api_baseline.json` in the same PR as
36
+ `pyproject.toml` changes.
37
+
38
+ **Never refresh the baseline for unrelated PRs.** A drift failure
39
+ during SDK upgrade is expected and intentional — it forces you to
40
+ inspect what changed.
@@ -1,8 +1,5 @@
1
- ---
2
- description: Run and debug codexloop autonomous sessions.
3
- globs:
4
- alwaysApply: false
5
- ---
1
+ # codexloop-run (Antigravity mirror of `.claude/skills/codexloop-run/SKILL.md`)
2
+
6
3
 
7
4
  # codexloop-run
8
5
 
@@ -0,0 +1,34 @@
1
+ # codexloop-testing (Antigravity mirror of `.claude/skills/codexloop-testing/SKILL.md`)
2
+
3
+
4
+ # codexloop testing
5
+
6
+ ```
7
+ tests/domain/ # pure unit + Hypothesis
8
+ tests/application/ # fakes for every port (application/interfaces/)
9
+ tests/infrastructure/ # adapters
10
+ tests/shim/ # fake_codex.py + fake_appserver.py — executable fakes
11
+ tests/live/ # marker: live — real OpenAI account, opt-in
12
+ ```
13
+
14
+ ```bash
15
+ pytest # skips live (default -m "not live and not system")
16
+ pytest -m system # real FS/git + scripted agent
17
+ pytest -m live # needs OPENAI_API_KEY
18
+ ```
19
+
20
+ - **Fakes over mocks.** Implement the `Protocol`; `mypy --strict` checks it.
21
+ - **Executable shims.** `fake_codex.py` and `fake_appserver.py` in
22
+ `tests/shim/` are genuine executables driven by env vars — the only such
23
+ fakes in the fleet. They let you script exact output sequences without
24
+ touching the OpenAI SDK.
25
+ - **No `time.sleep` in tests.** `FakeClock` / `FakeSleeper`.
26
+ - Hypothesis for numeric / time-based invariants.
27
+ - `# pragma: no cover` needs a reason.
28
+ - **100% branch coverage per layer**, enforced by gate:
29
+ ```bash
30
+ pytest -q --cov=codexloop.domain --cov-fail-under=100
31
+ pytest -q --cov=codexloop.application --cov-fail-under=100
32
+ pytest -q --cov=codexloop.infrastructure --cov-fail-under=100
33
+ pytest -q --cov=codexloop.cli --cov-fail-under=100
34
+ ```
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: codexloop-architecture
3
+ description: Onion layers for codexloop (domain, application, infrastructure, cli), import-linter, and where new code belongs. Use before adding a module under src/codexloop/.
4
+ allowed-tools: Read Grep Glob Bash(lint-imports)
5
+ ---
6
+
7
+ # codexloop architecture
8
+
9
+ Dependencies point inward. `import-linter` enforces this in CI.
10
+
11
+ ```
12
+ src/codexloop/
13
+ ├── domain/ # PURE. stdlib only. No I/O, no async, no third-party.
14
+ ├── application/ # Protocol ports + use cases. Imports domain + stdlib.
15
+ ├── infrastructure/ # Adapters. ONLY layer that may import openai.
16
+ ├── cli/ # Typer. Calls application via bootstrap.
17
+ └── bootstrap.py # Composition root — the ONE module that sees every layer.
18
+ ```
19
+
20
+ ## Where does new code go?
21
+
22
+ 1. Touches FS, network, clock, or an SDK? → `infrastructure/`, behind a
23
+ `Protocol` in `application/interfaces/`. Never `import openai`
24
+ elsewhere.
25
+ 2. Pure decision, zero I/O? → `domain/`. Examples: `classify.py`,
26
+ `waiting.py`, `completion.py`, `capacity.py`.
27
+ 3. Orchestration (port → domain → port)? → `application/`.
28
+ 4. Argument parsing / terminal formatting? → `cli/`.
29
+
30
+ When in doubt, push logic inward. `lint-imports` names the broken contract.
31
+
32
+ See ADR 0001.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: codexloop-completion
3
+ description: Three-layer completion evaluation (structured output → marker → continue), capacity rejection outranks completion claim. Use when working with completion.py.
4
+ allowed-tools: Read Grep
5
+ ---
6
+
7
+ # codexloop completion detection
8
+
9
+ `CompletionEvaluator` in `domain/completion.py` maps `TurnSignals` +
10
+ `CapacityState` into a `CompletionVerdict`.
11
+
12
+ ## CompletionVerdict variants
13
+
14
+ ```python
15
+ Done # task fully complete
16
+ Continue # remaining: list[str]
17
+ Blocked # reason: str — human intervention needed
18
+ ```
19
+
20
+ ## Three-layer evaluation
21
+
22
+ **Capacity rejection always outranks a completion claim.** If the turn is
23
+ not `Available`, return `Continue` regardless of structured output or
24
+ markers.
25
+
26
+ For an `Available` turn, the layers are:
27
+
28
+ 1. **Structured output** (`StructuredOutput` tool call result):
29
+ - `blocked_on` set → `Blocked(reason=blocked_on)`.
30
+ - `complete: true` and `remaining_work: []` → `Done`.
31
+ - `complete: true` but `remaining_work` not empty → `Continue`.
32
+ - `complete: false` → `Continue(remaining=remaining_work)`.
33
+
34
+ 2. **Marker on own line**: if `CODEXLOOP_TASK_FULLY_COMPLETE` appears on
35
+ its own line in the final message → `Done`.
36
+
37
+ 3. **Fallback**: `Continue(remaining=[])`.
38
+
39
+ The marker check uses `_marker_on_own_line(message, done_marker)`: the
40
+ string must be the only non-whitespace on the line. Partial matches or
41
+ inline occurrences do not count.
42
+
43
+ **Never treat a non-`Available` turn as `Done`.** Rate-limit windows and
44
+ transient errors are waitable; completion is deferred until capacity
45
+ returns.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: codexloop-docs
3
+ description: mkdocs-material, ADR structure, and doc build/serve commands. Use when adding documentation.
4
+ allowed-tools: Read Bash(mkdocs *)
5
+ ---
6
+
7
+ # codexloop docs
8
+
9
+ User-facing documentation lives in `docs/` and is built with
10
+ mkdocs-material.
11
+
12
+ ## Structure
13
+
14
+ ```
15
+ docs/
16
+ ├── index.md # landing page
17
+ ├── getting-started.md
18
+ ├── guides/ # how-to guides
19
+ │ └── rest-api-surface.md
20
+ ├── architecture/
21
+ │ ├── index.md
22
+ │ └── adr/ # Architecture Decision Records
23
+ │ ├── index.md
24
+ │ ├── 0001-onion-import-linter.md
25
+ │ └── 0002-subprocess-codex-exec.md
26
+ ├── contributing.md
27
+ └── publishing.md
28
+ ```
29
+
30
+ ## Commands
31
+
32
+ ```bash
33
+ mkdocs serve # live preview at http://127.0.0.1:8000
34
+ mkdocs build --strict # fail on warnings
35
+ ```
36
+
37
+ `--strict` runs in CI via `.github/workflows/docs.yml`.
38
+
39
+ ## ADRs
40
+
41
+ Architecture Decision Records follow the Nygard format. Each ADR gets a
42
+ number (0001, 0002, ...) and a kebab-case title. Add new ADRs to
43
+ `docs/architecture/adr/index.md`.
44
+
45
+ ## Excluded paths
46
+
47
+ `mkdocs.yml` excludes `plans/**` and `superpowers/**` from the built
48
+ site. These are workspace-specific and not user-facing.
49
+
50
+ ## Before pushing doc changes
51
+
52
+ Run `mkdocs build --strict` to catch broken links, missing pages, and
53
+ markdown errors.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: codexloop-quota-and-capacity
3
+ description: QuotaExhausted has no reset field, body-first classification ladder, and waitability rules. Use when working with capacity.py or classify.py.
4
+ allowed-tools: Read Grep
5
+ ---
6
+
7
+ # codexloop quota and capacity
8
+
9
+ `QuotaExhausted` is a billing wall with no `resets_at` — it is **never
10
+ waitable** and always needs a human to top up. Rate-limit windows *are*
11
+ waitable.
12
+
13
+ ## CapacityState variants
14
+
15
+ ```python
16
+ Available # green light
17
+ ThrottleExhausted # retry_after: timedelta | None
18
+ WindowExhausted # resets_at: datetime | None, window: str
19
+ QuotaExhausted # reason: str — TERMINAL, never waitable
20
+ AuthFailed # reason: str — TERMINAL
21
+ TransientBackendError # retry_after: timedelta | None
22
+ ```
23
+
24
+ `is_waitable(state)` returns `False` only for `QuotaExhausted` and
25
+ `AuthFailed`.
26
+
27
+ ## Body-first classification
28
+
29
+ `classify(signals)` in `domain/classify.py` maps `TurnSignals` to a
30
+ `CapacityState` using this ladder:
31
+
32
+ 1. **Body wins.** `error.code` / `error.type` outrank HTTP status.
33
+ 2. Auth: `error.code` / `error.type` in `ErrorClass.AUTH`, or status 401
34
+ → `AuthFailed`.
35
+ 3. Quota: `error.code` / `error.type` in `ErrorClass.QUOTA` →
36
+ `QuotaExhausted` (terminal).
37
+ 4. Window: `ErrorClass.WINDOW` → `WindowExhausted` with `resets_at` from
38
+ plan windows.
39
+ 5. Throttle: `ErrorClass.THROTTLE` → `ThrottleExhausted` with
40
+ `retry_after`.
41
+ 6. Transient: `ErrorClass.TRANSIENT` or status 5xx →
42
+ `TransientBackendError`.
43
+ 7. Status 429 with no body marker → `WindowExhausted(resets_at=None)`.
44
+ 8. Fallback: `Available`.
45
+
46
+ High `used_percent` never outranks a billing marker. Completion claims
47
+ never outrank capacity rejection.
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: codexloop-releasing
3
+ description: release-please, gitflow (develop → main), TestPyPI + PyPI publishing, and the known publish-testpypi gap. Use before cutting a release.
4
+ allowed-tools: Read Bash(git *)
5
+ ---
6
+
7
+ # codexloop releasing
8
+
9
+ ## Gitflow
10
+
11
+ ```
12
+ develop (default branch) → main (releases)
13
+ ```
14
+
15
+ 1. Feature PRs squash into `develop`.
16
+ 2. `develop` merge-commits into `main` when ready to release.
17
+ 3. release-please opens a PR on `main` when it detects conventional
18
+ commits since the last tag.
19
+ 4. Merging the release PR publishes to PyPI.
20
+
21
+ ## Workflows
22
+
23
+ - **`ci.yml`**: runs on every push. Tests, linting, type checks, per-layer
24
+ coverage, import-linter, bandit, pip-audit.
25
+ - **`publish-testpypi.yml`**: publishes to TestPyPI on every `develop`
26
+ push. **Known gap: no test gate.** This workflow builds and publishes
27
+ without running tests first. It trusts that CI passed.
28
+ - **`release-please.yml`**: opens a release PR on `main` when conventional
29
+ commits land. Merging that PR publishes to PyPI (via GitHub Actions +
30
+ PyPI trusted publishing).
31
+
32
+ ## release-please
33
+
34
+ Configured in `release-please-config.json`:
35
+
36
+ ```json
37
+ {
38
+ "packages": {
39
+ ".": {
40
+ "release-type": "python",
41
+ "package-name": "codexloop",
42
+ "changelog-path": "CHANGELOG.md"
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ It maintains `CHANGELOG.md` automatically from conventional commits.
49
+
50
+ ## Before merging develop → main
51
+
52
+ 1. All CI gates green on `develop`.
53
+ 2. TestPyPI publish succeeded (workflow run shows no errors).
54
+ 3. CHANGELOG.md reflects all user-facing changes since last release.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: codexloop-rest-surface
3
+ description: Generated `codexloop api` command tree, api_baseline.json drift gate, and how to refresh the baseline. Use when SDK upgrades change the surface.
4
+ allowed-tools: Read Bash(codexloop api *)
5
+ ---
6
+
7
+ # codexloop REST surface
8
+
9
+ `codexloop api` generates a 1:1 CLI mirror of the OpenAI Python SDK's REST
10
+ methods. The tree is code-generated from the SDK itself, not maintained by
11
+ hand.
12
+
13
+ ## api_baseline.json drift gate
14
+
15
+ `api_baseline.json` freezes the **OpenAI SDK's** method count and list,
16
+ not codexloop's. It is a snapshot of what the SDK exposes, not what
17
+ codexloop adds.
18
+
19
+ A test fails when:
20
+
21
+ - The SDK adds or removes methods (changes `method_count`).
22
+ - Methods appear or disappear from the `methods` list.
23
+ - `local_helpers` (like `chat.completions.stream`) change.
24
+
25
+ This gate prevents SDK upgrades from silently altering the API surface
26
+ without review.
27
+
28
+ ## Refreshing the baseline
29
+
30
+ After an intentional SDK upgrade, refresh the baseline:
31
+
32
+ ```bash
33
+ codexloop api --help # generates the tree
34
+ # The test writes the new baseline to api_baseline.json
35
+ pytest tests/cli/test_api.py --update-baseline
36
+ ```
37
+
38
+ Commit the updated `api_baseline.json` in the same PR as
39
+ `pyproject.toml` changes.
40
+
41
+ **Never refresh the baseline for unrelated PRs.** A drift failure
42
+ during SDK upgrade is expected and intentional — it forces you to
43
+ inspect what changed.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: codexloop-testing
3
+ description: Fakes over mocks, FakeClock/FakeSleeper, Hypothesis, pytest markers, per-layer 100% coverage. Consult before adding tests or mocks.
4
+ allowed-tools: Read Grep Glob Bash(pytest *)
5
+ ---
6
+
7
+ # codexloop testing
8
+
9
+ ```
10
+ tests/domain/ # pure unit + Hypothesis
11
+ tests/application/ # fakes for every port (application/interfaces/)
12
+ tests/infrastructure/ # adapters
13
+ tests/shim/ # fake_codex.py + fake_appserver.py — executable fakes
14
+ tests/live/ # marker: live — real OpenAI account, opt-in
15
+ ```
16
+
17
+ ```bash
18
+ pytest # skips live (default -m "not live and not system")
19
+ pytest -m system # real FS/git + scripted agent
20
+ pytest -m live # needs OPENAI_API_KEY
21
+ ```
22
+
23
+ - **Fakes over mocks.** Implement the `Protocol`; `mypy --strict` checks it.
24
+ - **Executable shims.** `fake_codex.py` and `fake_appserver.py` in
25
+ `tests/shim/` are genuine executables driven by env vars — the only such
26
+ fakes in the fleet. They let you script exact output sequences without
27
+ touching the OpenAI SDK.
28
+ - **No `time.sleep` in tests.** `FakeClock` / `FakeSleeper`.
29
+ - Hypothesis for numeric / time-based invariants.
30
+ - `# pragma: no cover` needs a reason.
31
+ - **100% branch coverage per layer**, enforced by gate:
32
+ ```bash
33
+ pytest -q --cov=codexloop.domain --cov-fail-under=100
34
+ pytest -q --cov=codexloop.application --cov-fail-under=100
35
+ pytest -q --cov=codexloop.infrastructure --cov-fail-under=100
36
+ pytest -q --cov=codexloop.cli --cov-fail-under=100
37
+ ```
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: codexloop-architecture
3
+ description: Onion layers for codexloop (domain, application, infrastructure, cli), import-linter, and where new code belongs. Use before adding a module under src/codexloop/.
4
+ allowed-tools: Read Grep Glob Bash(lint-imports)
5
+ ---
6
+
7
+ # codexloop architecture
8
+
9
+ Dependencies point inward. `import-linter` enforces this in CI.
10
+
11
+ ```
12
+ src/codexloop/
13
+ ├── domain/ # PURE. stdlib only. No I/O, no async, no third-party.
14
+ ├── application/ # Protocol ports + use cases. Imports domain + stdlib.
15
+ ├── infrastructure/ # Adapters. ONLY layer that may import openai.
16
+ ├── cli/ # Typer. Calls application via bootstrap.
17
+ └── bootstrap.py # Composition root — the ONE module that sees every layer.
18
+ ```
19
+
20
+ ## Where does new code go?
21
+
22
+ 1. Touches FS, network, clock, or an SDK? → `infrastructure/`, behind a
23
+ `Protocol` in `application/interfaces/`. Never `import openai`
24
+ elsewhere.
25
+ 2. Pure decision, zero I/O? → `domain/`. Examples: `classify.py`,
26
+ `waiting.py`, `completion.py`, `capacity.py`.
27
+ 3. Orchestration (port → domain → port)? → `application/`.
28
+ 4. Argument parsing / terminal formatting? → `cli/`.
29
+
30
+ When in doubt, push logic inward. `lint-imports` names the broken contract.
31
+
32
+ See ADR 0001.