outerloop-science 0.4.0rc1__tar.gz → 0.6.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 (348) hide show
  1. outerloop_science-0.6.0/.claude-plugin/marketplace.json +14 -0
  2. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.pre-commit-config.yaml +1 -1
  3. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CHANGELOG.md +110 -0
  4. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CITATION.cff +2 -2
  5. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CONTRIBUTING.md +13 -0
  6. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/PKG-INFO +30 -6
  7. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/README.md +29 -5
  8. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/RELEASING.md +7 -4
  9. outerloop_science-0.6.0/docs/assets/loop-dark.svg +86 -0
  10. outerloop_science-0.6.0/docs/assets/loop.svg +86 -0
  11. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/accelerators.md +13 -9
  12. outerloop_science-0.6.0/docs/design/forge.md +318 -0
  13. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/lifecycle.md +4 -2
  14. outerloop_science-0.6.0/docs/design/personal-token.md +268 -0
  15. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/roles.md +8 -9
  16. outerloop_science-0.6.0/docs/design/trajectory.md +67 -0
  17. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/endpoints.md +9 -0
  18. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/getting-started.md +33 -3
  19. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/index.md +3 -0
  20. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/install.md +91 -9
  21. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/operate.md +4 -1
  22. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/cli.md +42 -2
  23. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/contract.md +16 -2
  24. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/environment.md +73 -5
  25. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reviewer.md +4 -1
  26. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/roadmap.md +10 -0
  27. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/session-capture.md +5 -3
  28. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/storage.md +1 -1
  29. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/examples/review.yml +2 -0
  30. outerloop_science-0.6.0/plugins/outerloop/.claude-plugin/plugin.json +10 -0
  31. outerloop_science-0.6.0/plugins/outerloop/.codex-plugin/plugin.json +19 -0
  32. outerloop_science-0.6.0/plugins/outerloop/skills/contract/SKILL.md +41 -0
  33. outerloop_science-0.6.0/plugins/outerloop/skills/operate/SKILL.md +52 -0
  34. outerloop_science-0.6.0/plugins/outerloop/skills/setup/SKILL.md +82 -0
  35. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/pyproject.toml +1 -0
  36. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_deploy.sh +5 -3
  37. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/__init__.py +1 -1
  38. outerloop_science-0.6.0/src/outerloop/agent_text.py +343 -0
  39. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/attempt.py +455 -118
  40. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/author_overrides.py +11 -7
  41. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/brief.py +3 -1
  42. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/cli.py +313 -12
  43. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/climbboard.py +135 -2
  44. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/compute.py +80 -27
  45. outerloop_science-0.6.0/src/outerloop/containment/__init__.py +135 -0
  46. outerloop_science-0.6.0/src/outerloop/containment/macos.sb +18 -0
  47. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/contract.py +22 -2
  48. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/dispatch.py +156 -10
  49. outerloop_science-0.6.0/src/outerloop/forge.py +253 -0
  50. outerloop_science-0.6.0/src/outerloop/forge_local.py +1594 -0
  51. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/github.py +132 -107
  52. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/guidance_pack.py +3 -1
  53. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness.py +88 -12
  54. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness_cli.py +32 -5
  55. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hermes_capture.py +20 -1
  56. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/image.py +13 -3
  57. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/inbox.py +61 -25
  58. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/init.py +286 -14
  59. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/intake.py +3 -4
  60. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/launchlog.py +24 -0
  61. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_branch.py +17 -8
  62. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_events.py +26 -15
  63. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_migrate.py +12 -9
  64. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain.py +15 -7
  65. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain_post_cli.py +1 -1
  66. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/markers.py +20 -0
  67. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/measure.py +79 -6
  68. outerloop_science-0.6.0/src/outerloop/number_check.py +86 -0
  69. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/operator_limits.py +35 -5
  70. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/orchestrator.py +268 -22
  71. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/posting.py +24 -4
  72. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/progress.py +27 -7
  73. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review.py +15 -12
  74. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_agent.py +61 -6
  75. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_post_cli.py +26 -0
  76. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_summarize_cli.py +26 -3
  77. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/role_runner.py +7 -1
  78. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/session_evidence.py +106 -9
  79. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/status.py +11 -2
  80. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/steward.py +43 -30
  81. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/syscall.py +13 -14
  82. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/syscall_cli.py +57 -16
  83. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/tick.py +200 -84
  84. outerloop_science-0.6.0/src/outerloop/tool_calls.py +296 -0
  85. outerloop_science-0.6.0/src/outerloop/trajectory.py +332 -0
  86. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verifier.py +21 -9
  87. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/conftest.py +20 -0
  88. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/README.md +5 -0
  89. outerloop_science-0.6.0/tests/fixtures/climb-status-legacy.json +24 -0
  90. outerloop_science-0.6.0/tests/fixtures/session_index_legacy.json +19 -0
  91. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/ledger_fake.py +18 -0
  92. outerloop_science-0.6.0/tests/test_agent_plugin.py +31 -0
  93. outerloop_science-0.6.0/tests/test_agent_text.py +177 -0
  94. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_app_permissions.py +33 -0
  95. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_attempt.py +517 -552
  96. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_attempt_review.py +92 -106
  97. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_author_overrides.py +131 -2
  98. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_brief.py +3 -2
  99. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_climbboard.py +198 -80
  100. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_bridge.py +56 -0
  101. outerloop_science-0.6.0/tests/test_containment.py +180 -0
  102. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract.py +38 -2
  103. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_switches.py +16 -0
  104. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_default_claude_model.py +11 -3
  105. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_dispatch.py +246 -0
  106. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_endpoints.py +58 -1
  107. outerloop_science-0.6.0/tests/test_forge.py +56 -0
  108. outerloop_science-0.6.0/tests/test_forge_local.py +249 -0
  109. outerloop_science-0.6.0/tests/test_forge_local_e2e.py +220 -0
  110. outerloop_science-0.6.0/tests/test_forge_local_records.py +610 -0
  111. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_github.py +87 -158
  112. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hardening.py +0 -6
  113. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_harness.py +154 -178
  114. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_harness_pins.py +48 -0
  115. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hermes_author.py +7 -1
  116. outerloop_science-0.6.0/tests/test_identity.py +80 -0
  117. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_inbox.py +50 -89
  118. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_init.py +474 -269
  119. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_install_harness.py +10 -2
  120. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_launchlog.py +8 -3
  121. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_ledger_migrate.py +25 -4
  122. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_local_compute.py +124 -138
  123. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_maintain.py +3 -0
  124. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_measure.py +59 -0
  125. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_messages.py +8 -0
  126. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_end.py +9 -1
  127. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_limits.py +30 -0
  128. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_orchestrator.py +258 -126
  129. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_posting.py +56 -2
  130. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_progress.py +9 -0
  131. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_agent.py +103 -1
  132. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_summarize.py +24 -1
  133. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_session_evidence.py +175 -9
  134. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_start.py +173 -197
  135. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_status.py +36 -0
  136. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_steward.py +1 -1
  137. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_syscall.py +65 -86
  138. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_syscall_cli.py +50 -0
  139. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick.py +622 -542
  140. outerloop_science-0.6.0/tests/test_tool_calls.py +281 -0
  141. outerloop_science-0.6.0/tests/test_trajectory.py +222 -0
  142. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verifier.py +16 -0
  143. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_version.py +1 -1
  144. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/uv.lock +122 -122
  145. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.gitignore +0 -0
  146. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.python-version +0 -0
  147. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CLAUDE.md +0 -0
  148. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/LICENSE +0 -0
  149. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/NOTICE +0 -0
  150. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/SECURITY.md +0 -0
  151. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/containers/README.md +0 -0
  152. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/containers/agent-py312.def +0 -0
  153. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon-dark.svg +0 -0
  154. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon-light.svg +0 -0
  155. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon.svg +0 -0
  156. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-apple-touch-icon.png +0 -0
  157. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-favicon.png +0 -0
  158. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-favicon.svg +0 -0
  159. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/community.md +0 -0
  160. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/concurrency.md +0 -0
  161. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/contract.md +0 -0
  162. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-environment.md +0 -0
  163. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-protocols.md +0 -0
  164. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-substrate.md +0 -0
  165. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/architecture.md +0 -0
  166. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/base-reintegration.md +0 -0
  167. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/compute-cloud.md +0 -0
  168. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/consolidation.md +0 -0
  169. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/dispatcher.md +0 -0
  170. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/eval-cache.md +0 -0
  171. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/external.md +0 -0
  172. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/github-app-auth.md +0 -0
  173. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/headline.md +0 -0
  174. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/judge-placement.md +0 -0
  175. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/meta.md +0 -0
  176. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/model-gateway.md +0 -0
  177. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/multi-cluster.md +0 -0
  178. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/onboarding.md +0 -0
  179. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/orchestrator-verify.md +0 -0
  180. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/public-surface.md +0 -0
  181. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-lines.md +0 -0
  182. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-loop-buildout.md +0 -0
  183. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-loop.md +0 -0
  184. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/resident-tick.md +0 -0
  185. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/review-placement.md +0 -0
  186. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/reviewer-infra.md +0 -0
  187. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/role-cli.md +0 -0
  188. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/scaling.md +0 -0
  189. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/session-watcher.md +0 -0
  190. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/how-it-works.md +0 -0
  191. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/javascripts/figures.js +0 -0
  192. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/messages.md +0 -0
  193. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/inbox.md +0 -0
  194. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/syscalls.md +0 -0
  195. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/stylesheets/figures.css +0 -0
  196. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/stylesheets/site.css +0 -0
  197. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/validation/author-syscalls.md +0 -0
  198. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/mkdocs.yml +0 -0
  199. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/circle-half.svg +0 -0
  200. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/moon.svg +0 -0
  201. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/search.svg +0 -0
  202. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/sun.svg +0 -0
  203. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/lab/github.svg +0 -0
  204. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/main.html +0 -0
  205. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/partials/logo.html +0 -0
  206. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/README.md +0 -0
  207. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/docs/build.sh +0 -0
  208. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/docs/hooks.py +0 -0
  209. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_bridge.sh +0 -0
  210. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_claude.sh +0 -0
  211. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_codex.sh +0 -0
  212. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_hermes.sh +0 -0
  213. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/requeue_moved_successors.sh +0 -0
  214. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/setup_branch_protection.sh +0 -0
  215. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/sweep_git_locks.sh +0 -0
  216. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_chain.sbatch +0 -0
  217. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_resident.sh +0 -0
  218. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/__main__.py +0 -0
  219. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/appauth.py +0 -0
  220. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/appmanifest.py +0 -0
  221. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_install.py +0 -0
  222. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_runtime/pyproject.toml +0 -0
  223. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_runtime/uv.lock +0 -0
  224. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/codex_bridge.py +0 -0
  225. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/codex_requirements.toml +0 -0
  226. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/contract_cli.py +0 -0
  227. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/disk.py +0 -0
  228. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/endpoint_wait.py +0 -0
  229. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/endpoints.py +0 -0
  230. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/evalcache.py +0 -0
  231. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/gpu_lanes.py +0 -0
  232. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness_pins.py +0 -0
  233. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harnesses.toml +0 -0
  234. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hermes_install.py +0 -0
  235. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/housekeeping.py +0 -0
  236. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hypothesis.py +0 -0
  237. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/instance.py +0 -0
  238. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/job_names.py +0 -0
  239. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/limits.py +0 -0
  240. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain_agent_cli.py +0 -0
  241. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/panel.py +0 -0
  242. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/paths.py +0 -0
  243. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/provenance.py +0 -0
  244. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/py.typed +0 -0
  245. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/rebind.py +0 -0
  246. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_agent_cli.py +0 -0
  247. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/roles.py +0 -0
  248. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/rolespec.py +0 -0
  249. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/runstate.py +0 -0
  250. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/style.py +0 -0
  251. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_agent.py +0 -0
  252. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_agent_cli.py +0 -0
  253. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_post_cli.py +0 -0
  254. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/watcher.py +0 -0
  255. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fakes.py +0 -0
  256. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_legacy.json +0 -0
  257. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_missing_model.json +0 -0
  258. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_missing_route.json +0 -0
  259. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/base_moved_cc4e5d7.json +0 -0
  260. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/default_contract_head.json +0 -0
  261. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/command.txt +0 -0
  262. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/exit-code +0 -0
  263. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/job.sh +0 -0
  264. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/provenance.json +0 -0
  265. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/stdout +0 -0
  266. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
  267. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/identity.json +0 -0
  268. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/inflight/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/command.txt +0 -0
  269. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/inflight/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/job.sh +0 -0
  270. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/inflight/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/provenance.json +0 -0
  271. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/inflight/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
  272. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/hermes_resume_legacy.json +0 -0
  273. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/hermes_sample_20260924.json +0 -0
  274. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/launches-before-provenance.jsonl +0 -0
  275. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/panel_wake_9ca3d7c.json +0 -0
  276. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/pre_contract_switches.json +0 -0
  277. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/baselines/main@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json +0 -0
  278. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/brief.txt +0 -0
  279. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/end-request.json +0 -0
  280. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/ended.json +0 -0
  281. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-provenance/command.txt +0 -0
  282. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-provenance/job.sh +0 -0
  283. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/command.txt +0 -0
  284. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/exit-code +0 -0
  285. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/job.sh +0 -0
  286. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/stdout +0 -0
  287. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
  288. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/generate.py.txt +0 -0
  289. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/identity.json +0 -0
  290. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/launches.jsonl +0 -0
  291. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/line.bundle +0 -0
  292. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/merged.json +0 -0
  293. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/open.json +0 -0
  294. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pending/owner__repo.json +0 -0
  295. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pending/owner__repo@agent-01.json +0 -0
  296. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pr-states.json +0 -0
  297. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/queue.json +0 -0
  298. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/rebind.json +0 -0
  299. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/sessionless.json +0 -0
  300. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/session_cost_legacy.json +0 -0
  301. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/suite_measurement_legacy.json +0 -0
  302. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/helpers.py +0 -0
  303. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_appauth.py +0 -0
  304. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_appmanifest.py +0 -0
  305. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_bot_aliases.py +0 -0
  306. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_bot_login.py +0 -0
  307. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_channel_dir.py +0 -0
  308. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_harness.py +0 -0
  309. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_hooks.py +0 -0
  310. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_host.py +0 -0
  311. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_compute.py +0 -0
  312. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_cli.py +0 -0
  313. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_names.py +0 -0
  314. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_disk.py +0 -0
  315. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_endpoint_wait.py +0 -0
  316. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_evalcache.py +0 -0
  317. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_gpu_lanes.py +0 -0
  318. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hermes_harness.py +0 -0
  319. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_housekeeping.py +0 -0
  320. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_image.py +0 -0
  321. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_import.py +0 -0
  322. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_instance.py +0 -0
  323. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_intake.py +0 -0
  324. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_ledger_events.py +0 -0
  325. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_lifecycle_cli.py +0 -0
  326. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_limits.py +0 -0
  327. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_markers.py +0 -0
  328. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_measure_and_decide.py +0 -0
  329. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_message.py +0 -0
  330. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_packaging.py +0 -0
  331. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_panel.py +0 -0
  332. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_paths.py +0 -0
  333. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_rebind.py +0 -0
  334. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_requeue_moved_successors.py +0 -0
  335. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review.py +0 -0
  336. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_agent_cli.py +0 -0
  337. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_hardening.py +0 -0
  338. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_policy.py +0 -0
  339. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_role_runner.py +0 -0
  340. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_rolespec.py +0 -0
  341. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_runstate.py +0 -0
  342. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_sweep_git_locks.py +0 -0
  343. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick_chain_successors.py +0 -0
  344. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick_resident.py +0 -0
  345. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tiers.py +0 -0
  346. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verify_agent.py +0 -0
  347. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verify_agent_cli.py +0 -0
  348. {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_watcher.py +0 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "outerloop",
3
+ "owner": {
4
+ "name": "Outerloop"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "outerloop",
9
+ "source": "./plugins/outerloop",
10
+ "category": "Productivity"
11
+ }
12
+ ],
13
+ "description": "Set up and operate Outerloop from your coding agent."
14
+ }
@@ -14,7 +14,7 @@ repos:
14
14
  - id: check-toml
15
15
 
16
16
  - repo: https://github.com/astral-sh/ruff-pre-commit
17
- rev: v0.16.6
17
+ rev: v0.17.1
18
18
  hooks:
19
19
  - id: ruff-check
20
20
  args: [--fix]
@@ -6,6 +6,81 @@ Versions follow [SemVer](https://semver.org).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.6.0] - 2026-10-26
10
+
11
+ ### Upgrading
12
+
13
+ No operator action is needed before upgrading; details in each entry.
14
+
15
+ What changes for runs in flight: runs started before the upgrade have no
16
+ trajectory until their next recorded event, and their earlier session events
17
+ count as author sessions. The first run to end creates the attestation key
18
+ `trajectory_attest.key`, owner-only, beside the operator settings file. On
19
+ macOS without an image, sessions, evaluations and panel lenses now run under
20
+ the Seatbelt profile, which allows outbound connections only to TCP port 443,
21
+ DNS and local ports.
22
+
23
+ Before rolling back: if you switched the author to a Claude subscription
24
+ token, switch back to an API key, since older kernels send the token as
25
+ `ANTHROPIC_API_KEY`. Older kernels ignore `trajectory.jsonl`, the attestation
26
+ key and `OUTERLOOP_AUTHOR_EFFORT`, and pending ledger records are unchanged.
27
+
28
+ ### Changes
29
+
30
+ - `OUTERLOOP_AUTHOR_EFFORT` sets the author's effort level (`low`, `medium`, `high`, `xhigh` or `max`) on every backend: Claude Code's `--effort` (the pinned 2.1.285 has the flag), Codex's `model_reasoning_effort` as a kernel-owned `-c` setting, and Hermes's `agent.reasoning_effort`. For Hermes the setting is written to the seeded `config.yaml`, and the capture wrapper also hands it to the agent, because `run_agent.main` builds its agent without a reasoning config and would otherwise ignore it. Unset keeps each harness's default. Panel judges and the steward ignore it, so a cheaper author does not change how its work is reviewed. Start, the tick and each wake refuse an unknown level. The setting is read when each session starts and is not stored in run records.
31
+ - Run endings append one `attest` trajectory event: an HMAC-SHA256 over the run id and chain head with a deployment key created owner-only beside the operator settings file, and `outerloop trajectory --verify` reports `attested` or `attestation mismatch`. Older kernels ignore the event; no ledger or PR-body change.
32
+ - The PR body gains a report-only Number check that lists values in the author's report matching no `measure` event or Experiments result when rounded to the report's decimals; nothing is blocked and no trajectory event is added.
33
+ - Session end records each tool call from the retained Claude or Codex log as a `tool.call` trajectory event, once per call even when a session resumes. `outerloop trajectory` and a new Process section in the PR body show counts by tool. Older kernels ignore these events.
34
+ - `outerloop status` shows a run's priced session cost as a lower bound when some legs are unpriced (a wake killed mid-turn leaves no usage event), for example `session-cost>=$4.2000 (1 unpriced)`, instead of hiding the priced part behind `unknown`; the status row and JSON gain the priced-leg count (#516).
35
+ - The pre-PR panel accepts a composite change — a PR that carries several changes — when the report gives each component's isolated measurement and the combination's under the same protocol and the combination is what the kernel measured. A bundle without those isolated measurements stays blocked (#489).
36
+ - Claude sessions can use a subscription token from `claude setup-token` (`sk-ant-oat...`). The harness sends it as `CLAUDE_CODE_OAUTH_TOKEN`, not `ANTHROPIC_API_KEY`, and `init` accepts it. A panel judge on a token runs `claude --safe-mode`, because `--bare` cannot read OAuth tokens. Both modes ignore the checkout's CLAUDE.md, hooks, plugins and MCP servers. The pinned Claude Code release (2.1.285) has `--safe-mode`.
37
+ - A session now hears once when a live sibling states a new or changed hypothesis (#360). The note names the sibling, quotes its hypothesis, and points to `siblings` for its launches and score. It is sent only when `channels.siblings` is on. Upgrading: the note uses the existing `note` kind, so an older kernel shows it as ordinary inbox text.
38
+ - A skills-only plugin for Claude Code and Codex sets up Outerloop, writes and validates the contract, and operates runs from the agent (#562). Install it with `/plugin marketplace add outerloop-science/outerloop` or `codex plugin marketplace add outerloop-science/outerloop`. Its setup skill offers a Claude subscription token from `claude setup-token` as the author credential.
39
+ - `outerloop trajectory <run-id>` now ends with the run's refusal count and its author models, for release canary comparisons; the agent-text inventory includes operator notes (#487, part 3). Session events record `role` (`author` or `judge`). Upgrading: session events written before this kernel have no `role` and count as author sessions.
40
+ - On macOS without an image, sessions, evaluations and panel lenses run under a packaged Seatbelt profile (`sandbox-exec`, #292): they write only the workspace and a scratch directory, read only system and toolchain paths, and connect out only to TCP port 443, DNS and local ports. Linux and Apptainer runs are unchanged.
41
+ - Kernel events now append to a per-run `trajectory.jsonl` with sequence numbers and a SHA-256 chain. `outerloop trajectory <run-id> [--verify] [--json]` reads it without changing run state. Operational files and their formats are unchanged; older kernels ignore the new file. Upgrading: runs started before this kernel have no trajectory and read as "no trajectory" until their next recorded event. No backfill is attempted.
42
+ - `measure` trajectory events carry provenance: the ledger's ruler digest (the same value a pending submission computes), the container image digest when an image is configured, and refs to the evaluation result files the kernel read. Self-reported measures record the ruler alone. Pending ledger records now ignore fields this kernel does not know, so a later release can add one without breaking this release's ledger read. Upgrading: no action needed; older kernels ignore the trajectory, and pending records are unchanged.
43
+ - Add a printable agent-text inventory and protocol wording lint, with clearer refusal recovery guidance (#487, parts 1–2).
44
+ - `BENCHMARKS.md` shows `—` instead of "provenance unknown" in the main-commit column of a baseline row that nothing has improved on yet, as on a freshly seeded repository.
45
+ - The README and the getting-started guide link to the quickstart repository. It runs two CPU benchmarks with the local forge and local compute, and needs no GitHub account or cluster (#563). The docs and the startup warning no longer say an uncontained session runs in a sandbox: on Linux without an image, it gets a scrubbed environment and its own home, but can read any file the account can.
46
+ - The advisory review covers exactly the head its triggering event named (`REVIEW_HEAD_SHA`, #462). If the PR has moved off that head, nothing is reviewed or posted. Otherwise the diff is read between fixed commits, every envelope records the reviewed `head_sha`, and the review is attached to that commit. When GitHub refuses its inline comments, the fallback is a body-only review on the same commit, never an unpinned comment (#569). The summarizer skips clean when its lenses read different heads. For a fork PR (`REVIEW_CHECKOUT_BASE=1`) the brief says the tree is the base branch and the change is only in the diff. Upgrading: envelopes without `head_sha` (from an older reviewer ref) still post; callers that do not pass REVIEW_HEAD_SHA behave as before.
47
+ - When check runs cannot be read on a token deployment, the warning now says the token cannot read them (fine-grained tokens have no checks permission) instead of asking for an App permission.
48
+
49
+ ## [0.5.0] - 2026-10-23
50
+
51
+ ### Upgrading
52
+
53
+ No operator action is needed before upgrading; details in each entry.
54
+
55
+ What changes for runs in flight: kernel comments, issues and pull requests
56
+ start carrying `<!-- outerloop:kernel -->`; the first tick republishes
57
+ `climb/status.json` in the new shape; a resumed Claude session captured
58
+ before the upgrade still overstates its cost.
59
+
60
+ Before rolling back: remove `slots` keys from `limits.toml`, and let local
61
+ jobs on GPU UUID ids (`GPU-...`) finish.
62
+
63
+ ### Changes
64
+
65
+ - Docs for personal-token mode: the install guide's personal-mode section (setup, how kernel posts are told apart, what GitHub no longer enforces, token reach, switching modes), the safety defaults in `operate.md`, `OUTERLOOP_IDENTITY` in the environment reference, `init --personal` in the CLI reference, and `personal: true` in the reviewer setup.
66
+ - Personal-token mode is selectable: `outerloop init --personal` takes the token `gh auth token` prints and writes it 0600 to the default PAT file (or uses a token file given with `--pat-file`), records its login as `OUTERLOOP_BOT_LOGIN`, and writes `OUTERLOOP_IDENTITY=personal`; `start` and the deploy step carry the setting into every tick. The kernel then posts as the person, so its own posts are told apart by the `outerloop:` marker rather than by login. The setup prints the trade-offs: no notifications for the kernel's activity, the `gh` token's repository-wide reach, and the reviewer workflow's `personal: true`. Upgrading: switching a personal deployment back to the App means releasing or closing claimed issues first — their claim comments were posted as the person, and the App's login check no longer counts them.
67
+ - One rule, `forge.is_kernel_post`, now decides whether a comment, issue or pull request is the kernel's, wherever the kernel asks. In personal mode (`OUTERLOOP_IDENTITY=personal`) the login is the person's, so a post is the kernel's only when its body also carries an `outerloop:` marker. Alias logins keep the login check alone. Kernel comments, issues and pull requests now carry `<!-- outerloop:kernel -->` unless they already carry a marker. When the kernel arms auto-merge it records the PR in the run's stage (`auto_merge_armed`) and clears the record once it disarms or sees auto-merge off; under the auto dial it withdraws only an arm that record claims, so a human's later arm is left alone. Upgrading: kernel posts now carry a marker, which an older kernel ignores. A stage without an `auto_merge_armed` record (every run armed before the upgrade) keeps the old `enabled_by.login` rule outside personal mode, so a PR the kernel armed before the upgrade is still withdrawn under the auto dial; rolling back ignores the field.
68
+ - The `siblings` view now shows each sibling's research instead of its last chat line: the run's stated hypothesis, its three most recent launches with `--why`, state and result line, the candidate score from the kernel's own gate measurement (never the agent's claim), and its PR, plus the target's five most recent endings with outcome and report title. `climb/status.json` gains `best_result` and `launches` per live run and a top-level `ended` list. Upgrading: no action needed; a snapshot written before this change reads as before (no launches, score or endings) and the first tick republishes it once in the new shape; rolling back is safe because an older reader ignores the added fields.
69
+ - Session records and the session index now carry the Claude Code version that ran, read from the binary's resolved path (the native installer's `versions/<x.y.z>` and the kernel's managed `harnesses/claude/<x.y.z>/` installs; the pin is not used, since an operator can point the kernel at any binary), so a resumed Claude session prices its cumulative resume totals once at the newest leg when it ran on Claude Code 2.1.277 or later. Codex is unchanged, and a Claude entry without a usable version keeps summing its legs (#515). Upgrading: no action needed; index entries written before this change carry no version, so a resumed Claude session captured before the upgrade still overstates its cost until those entries age out.
70
+ - `outerloop init` warns when the Claude or Codex CLI it finds is older than the pinned version and names `outerloop harness upgrade`, and says when the pre-PR panel stays off for lack of an image. The install guide covers seeding a private repository into the local forge.
71
+ - `outerloop pr merge` on the local forge authors the merge commit with the operator's git identity from system and global config (a repo-local identity in the directory it runs from is ignored); automatic merges keep the kernel's. Candidate snapshot commits are named `candidate snapshot: <run id>` instead of `dispatch snapshot`.
72
+ - Add an internal `Forge` seam behind the kernel's code-host operations; `OUTERLOOP_FORGE` accepts only `github` for now (no behavior change).
73
+ - Add the local forge backend's transport, refs and files over bare repositories (clone, branch and file reads and compare-and-swap writes); `OUTERLOOP_FORGE=local` is not selectable until pull requests, threads and issues exist.
74
+ - Add the local forge backend's records on `refs/outerloop/records`: pull requests, comment threads and the kernel's issues, with merge-commit transactions and recovery of merges made outside the kernel; user-visible inbox and self-merge text takes the forge's name.
75
+ - The local forge is selectable: `OUTERLOOP_FORGE=local` builds it from the state root, entry points need no GitHub credential or bot login, `outerloop init --forge local` bootstraps the bare repository, and `outerloop pr` lists, shows, comments on, merges and closes its pull requests.
76
+ - Local compute's GPU pool follows the loop's own `CUDA_VISIBLE_DEVICES`: when it is set at startup, those ids are the pool (jobs still get a subset), so two deployments on one host can be given disjoint GPUs. `OUTERLOOP_LOCAL_GPUS` caps the list, keeping the first ids; empty or `-1` means no GPUs. Jobs never see GPUs outside the loop's view: a job without an allocation inherits the loop's `CUDA_VISIBLE_DEVICES`. Fix: on local compute, the evaluated command now sees its job's GPU mask; the eval script's scrubbed environment (`env -i`, or apptainer `--cleanenv`) used to drop it, so evaluated code saw every GPU on the host. Slurm jobs are unchanged.
77
+ - Upgrading: an existing pool file (`gpus.json`) reads correctly, since holder keys stay the GPU index strings. Before rolling back to an older kernel, let jobs on non-integer ids (`GPU-...` UUIDs) finish: the older kernel cannot sort those holder keys.
78
+ - `limits.toml` accepts a per-target `slots` list (`[targets."owner/repo"]`, `slots = ["agent-04"]`): self-initiated runs take the first free listed agent identity, in order, instead of the lowest free `agent-01..agent-<width>`, so an operator can keep a slot's research line and author binding. Slots never add capacity (the attempt width still caps concurrency), running runs in unlisted slots are untouched, and `outerloop limits` shows the list. Without `slots`, behaviour is unchanged.
79
+ - Upgrading: existing `limits.toml` files need no change. Remove any `slots` key before rolling back to an older kernel, which treats it as unknown and fails the file closed.
80
+ - Refresh the toolchain within the existing bounds: pydantic 2.14.1, pydantic-core 2.50.1, ruff 0.17.1 and pre-commit 4.7.0; the ruff-pre-commit hook matches the locked Ruff. No source formatting or lint changes were needed.
81
+
82
+ ## [0.4.0] - 2026-10-20
83
+
9
84
  ### Upgrading
10
85
 
11
86
  Operator actions before upgrading (everything else needs no action; details
@@ -107,6 +182,38 @@ runs, and do not roll back while self-reported claims exist.
107
182
  without a compatibility change. Upgrading: no action needed; it appends an
108
183
  ordinary note from the kernel; a parked run that is not waiting on jobs wakes
109
184
  at the next tick to read it, and one waiting on jobs reads it when they end.
185
+ - `OUTERLOOP_UNCONTAINED=1` runs a cluster deployment without a container
186
+ runtime: sessions and evaluations run as Slurm jobs the way local mode runs
187
+ them without an image, the image is ignored, and the panel stays opt-in
188
+ (`OUTERLOOP_PANEL_UNCONTAINED=1`, now also carried by the chain's deploy
189
+ step). Without it, a cluster deployment with no image still services nothing,
190
+ and its log now names the setting. `outerloop start` now checks the fleet
191
+ default author with the tick's own author check, as it already did for
192
+ overrides, reading settings with the precedence the launched tick applies,
193
+ so a default the tick would refuse (a Codex or Hermes author without an
194
+ image, a Codex author without a Codex model) fails at start instead of
195
+ idling every tick.
196
+ - Multi-node benchmarks: a benchmark's `nodes` (default 1, up to 64) spreads
197
+ every dispatched job over that many nodes, with `gpus` per node. The eval
198
+ job `srun`s one task per node; each runs the command in its own checkout
199
+ with `NNODES`, `NODE_RANK`, `MASTER_ADDR`, `MASTER_PORT` and torchrun's
200
+ `PET_*` defaults set, node 0's output is the measurement, and a failing node
201
+ stops the rest. A requeued job clears the earlier attempt's per-node results
202
+ before it starts, and those rendezvous names (and any `PET_*`) are refused as
203
+ a `seed_env`. GPU-hour charges, budget checks, sweep pacing and the
204
+ operator's GPU ceiling count `nodes x gpus`. Uncontained Slurm deployments
205
+ only: a contained or local deployment refuses to launch attempts on such a
206
+ contract. Upgrading: one-node benchmarks keep their measurement signatures,
207
+ eval slots and cached baselines unchanged; cached baselines now record
208
+ their node count, and entries without one read as one node. A contract
209
+ that sets `nodes` fails to load on older kernels (unknown keys are
210
+ refused), so upgrade every fleet that services a target before adding it.
211
+ - `OUTERLOOP_OPERATOR_HARNESSES` lists harness CLIs the operator supplies, such
212
+ as a site-managed `claude` that authenticates by itself: `outerloop harness
213
+ upgrade` (and the deployment's automatic `--used` run) never replaces them or
214
+ rewrites their recorded paths, and `outerloop harness status` reports
215
+ `OPERATOR` instead of drift. Unknown names are refused. The chain's deploy
216
+ step re-reads it from `.env` every tick.
110
217
 
111
218
  ### Documentation
112
219
 
@@ -221,6 +328,9 @@ runs, and do not roll back while self-reported claims exist.
221
328
  Upgrading: run `outerloop harness upgrade codex`; deploys that run harness
222
329
  upgrades do this automatically. Existing single-binary installs are detected
223
330
  as drift and replaced with a verified pair.
331
+ - Uncontained sweep tasks now receive `SWEEP_INDEX`: the bare evaluation
332
+ branch runs the command under `env -i` and dropped it, so every task of a
333
+ sweep without an image ran the default configuration.
224
334
 
225
335
  ### Changed
226
336
 
@@ -13,5 +13,5 @@ authors:
13
13
  repository-code: "https://github.com/outerloop-science/outerloop"
14
14
  url: "https://outerloop.science"
15
15
  license: Apache-2.0
16
- version: 0.4.0rc1
17
- date-released: "2026-10-19"
16
+ version: 0.6.0
17
+ date-released: "2026-10-26"
@@ -61,6 +61,19 @@ uv run pytest
61
61
  `uv lock`; CI checks the lock.
62
62
  - Docs are plain prose. Short sentences, no metaphors, no internal jargon.
63
63
 
64
+ New agent-facing text must be reachable from `outerloop.agent_text.inventory()`.
65
+ Keep text with its renderer and add a representative rendering to the inventory;
66
+ review it with `python -m outerloop.agent_text`. The fast lint in
67
+ `tests/test_agent_text.py` checks protocol terms, syscall names, and refusal recovery
68
+ guidance. Keep refusals inline: the inventory reads explicit AST constructs listed in
69
+ `REFUSAL_CONSTRUCTS`, rendering f-string expressions as `{}`. Input constraints
70
+ use category `validation` and need no redundant next step. The syscall CLI mixes
71
+ constraints and state refusals in `ToolError`; `CLI_REFUSALS` identifies the latter
72
+ by function and call ordinal, so update it when adding or reordering those calls. Delivery reasons composed into a
73
+ refusal use category `reason`; the enclosing refusal carries recovery guidance.
74
+ Kernel refusals require a next step; any exception needs a specific reason beside
75
+ the lint rule.
76
+
64
77
  ## Tests
65
78
 
66
79
  | Tier | Marker | Runs |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: outerloop-science
3
- Version: 0.4.0rc1
3
+ Version: 0.6.0
4
4
  Summary: Autonomous research agents that improve the benchmark you point them at, one verified pull request at a time
5
5
  Project-URL: Homepage, https://outerloop.science
6
6
  Project-URL: Repository, https://github.com/outerloop-science/outerloop
@@ -41,6 +41,11 @@ change, runs the experiment on your cluster, and opens a pull request only
41
41
  when your benchmark actually improves. Every attempt ends in a short
42
42
  written report, including the attempts that failed.
43
43
 
44
+ <picture>
45
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/outerloop-science/outerloop/main/docs/assets/loop-dark.svg">
46
+ <img alt="One attempt: an agent proposes a change, runs the experiment on your GPUs, the kernel re-measures it against the base, judges review the claim, and a pull request opens with a written report. Without a real gain the attempt ends in a report and the next hypothesis starts." src="https://raw.githubusercontent.com/outerloop-science/outerloop/main/docs/assets/loop.svg" width="880">
47
+ </picture>
48
+
44
49
  You run it yourself, with your own keys, your own compute and your own
45
50
  repositories, and nothing reports back to us. It is built and used every
46
51
  day by the [Agentic Learning AI Lab](https://agenticlearning.ai) at NYU,
@@ -48,7 +53,24 @@ where it co-develops our research codebases.
48
53
 
49
54
  ## Get started
50
55
 
51
- Three commands and one file. You need a repo with a benchmark command, an
56
+ To see a run first, the [quickstart](https://github.com/outerloop-science/quickstart)
57
+ runs two CPU benchmarks on your own machine, with no GitHub account and no
58
+ cluster. You need Python 3.12 or later, [uv](https://docs.astral.sh/uv/), Git
59
+ 2.38 or later and an Anthropic API key:
60
+
61
+ ```bash
62
+ pip install outerloop-science
63
+ outerloop init --forge local --compute local --no-image --target me/quickstart \
64
+ --forge-source https://github.com/outerloop-science/quickstart
65
+ outerloop start
66
+ ```
67
+
68
+ On macOS, sessions and evaluations run under a Seatbelt profile: they write their
69
+ workspace and a scratch directory, read system and toolchain paths, and cannot read
70
+ the rest of your home. On Linux without a container they can read any file your
71
+ account can. Either way, use a spend-capped API key.
72
+
73
+ For your own repository: three commands and one file. You need a repo with a benchmark command, an
52
74
  API key for the model that will write the code, and a Slurm cluster or one
53
75
  machine with a GPU.
54
76
 
@@ -60,8 +82,10 @@ outerloop init # where the loop runs, which repo, which model and its key, y
60
82
  The wizard asks for a GitHub identity for the agents to open pull requests
61
83
  as. Pick `app` and it walks you through creating a GitHub App under your
62
84
  account and installing it on the repo. Pick `pat` if you already have a
63
- token, and it writes the config and the key files either way. Then add one
64
- file, `.outerloop.yaml`, to the repo you want improved:
85
+ token, and it writes the config and the key files either way. To try it
86
+ without GitHub, `outerloop init --forge local` keeps the repository and its
87
+ pull requests in a git repository on the same machine. Then add one file,
88
+ `.outerloop.yaml`, to the repo you want improved:
65
89
 
66
90
  ```yaml
67
91
  benchmarks:
@@ -128,8 +152,8 @@ build. See [the reviewer guide](https://docs.outerloop.science/reviewer/).
128
152
  output are rendered to the agent as fenced data, not instructions, which
129
153
  lowers the risk of injected text being followed without guaranteeing it.
130
154
  A contained session gets no GitHub credential in its environment and
131
- cannot read the operator's key files; an uncontained local session runs
132
- as your user and can read any file you can, key files included.
155
+ cannot read the operator's key files. Without a container, a macOS session
156
+ runs under Seatbelt; a Linux session can read any file you can, key files included.
133
157
  - **Budgets in code.** Launches, GPU-hours, and runs per week are enforced
134
158
  by the kernel, not left to the agent.
135
159
  - **No model lock-in.** Claude Code, Codex, and hermes-agent are wired
@@ -17,6 +17,11 @@ change, runs the experiment on your cluster, and opens a pull request only
17
17
  when your benchmark actually improves. Every attempt ends in a short
18
18
  written report, including the attempts that failed.
19
19
 
20
+ <picture>
21
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/outerloop-science/outerloop/main/docs/assets/loop-dark.svg">
22
+ <img alt="One attempt: an agent proposes a change, runs the experiment on your GPUs, the kernel re-measures it against the base, judges review the claim, and a pull request opens with a written report. Without a real gain the attempt ends in a report and the next hypothesis starts." src="https://raw.githubusercontent.com/outerloop-science/outerloop/main/docs/assets/loop.svg" width="880">
23
+ </picture>
24
+
20
25
  You run it yourself, with your own keys, your own compute and your own
21
26
  repositories, and nothing reports back to us. It is built and used every
22
27
  day by the [Agentic Learning AI Lab](https://agenticlearning.ai) at NYU,
@@ -24,7 +29,24 @@ where it co-develops our research codebases.
24
29
 
25
30
  ## Get started
26
31
 
27
- Three commands and one file. You need a repo with a benchmark command, an
32
+ To see a run first, the [quickstart](https://github.com/outerloop-science/quickstart)
33
+ runs two CPU benchmarks on your own machine, with no GitHub account and no
34
+ cluster. You need Python 3.12 or later, [uv](https://docs.astral.sh/uv/), Git
35
+ 2.38 or later and an Anthropic API key:
36
+
37
+ ```bash
38
+ pip install outerloop-science
39
+ outerloop init --forge local --compute local --no-image --target me/quickstart \
40
+ --forge-source https://github.com/outerloop-science/quickstart
41
+ outerloop start
42
+ ```
43
+
44
+ On macOS, sessions and evaluations run under a Seatbelt profile: they write their
45
+ workspace and a scratch directory, read system and toolchain paths, and cannot read
46
+ the rest of your home. On Linux without a container they can read any file your
47
+ account can. Either way, use a spend-capped API key.
48
+
49
+ For your own repository: three commands and one file. You need a repo with a benchmark command, an
28
50
  API key for the model that will write the code, and a Slurm cluster or one
29
51
  machine with a GPU.
30
52
 
@@ -36,8 +58,10 @@ outerloop init # where the loop runs, which repo, which model and its key, y
36
58
  The wizard asks for a GitHub identity for the agents to open pull requests
37
59
  as. Pick `app` and it walks you through creating a GitHub App under your
38
60
  account and installing it on the repo. Pick `pat` if you already have a
39
- token, and it writes the config and the key files either way. Then add one
40
- file, `.outerloop.yaml`, to the repo you want improved:
61
+ token, and it writes the config and the key files either way. To try it
62
+ without GitHub, `outerloop init --forge local` keeps the repository and its
63
+ pull requests in a git repository on the same machine. Then add one file,
64
+ `.outerloop.yaml`, to the repo you want improved:
41
65
 
42
66
  ```yaml
43
67
  benchmarks:
@@ -104,8 +128,8 @@ build. See [the reviewer guide](https://docs.outerloop.science/reviewer/).
104
128
  output are rendered to the agent as fenced data, not instructions, which
105
129
  lowers the risk of injected text being followed without guaranteeing it.
106
130
  A contained session gets no GitHub credential in its environment and
107
- cannot read the operator's key files; an uncontained local session runs
108
- as your user and can read any file you can, key files included.
131
+ cannot read the operator's key files. Without a container, a macOS session
132
+ runs under Seatbelt; a Linux session can read any file you can, key files included.
109
133
  - **Budgets in code.** Launches, GPU-hours, and runs per week are enforced
110
134
  by the kernel, not left to the agent.
111
135
  - **No model lock-in.** Claude Code, Codex, and hermes-agent are wired
@@ -43,21 +43,24 @@ wording does not reach a parked run unless its deduplication key changes.
43
43
  run with an open PR, a run whose PR merged, and an ended run. A dev or rc pre-release still bumps the version (PyPI never
44
44
  accepts a version twice, so the next one is `.dev1`, `rc2`, ...) but leaves
45
45
  `[Unreleased]` in place until the final release.
46
- 3. `git tag vX.Y.Z && git push origin vX.Y.Z`. The `release` workflow builds
46
+ 3. Pre-release canary runs report `refusals` per run by author model from
47
+ `outerloop trajectory <run-id>`. If refusals per run rise against the previous
48
+ release, explain why in the release PR before shipping.
49
+ 4. `git tag vX.Y.Z && git push origin vX.Y.Z`. The `release` workflow builds
47
50
  and publishes `outerloop-science` to PyPI through Trusted Publishing; the
48
51
  one-time PyPI setup is described at the top of
49
52
  `.github/workflows/release.yml`.
50
- 4. Once the `release` workflow run for the tag is green (`gh run watch` on
53
+ 5. Once the `release` workflow run for the tag is green (`gh run watch` on
51
54
  it), `pip install outerloop-science==X.Y.Z` in a fresh venv, then
52
55
  `outerloop --help`. This comes before the GitHub release: publishing it is
53
56
  what Discord announces, so nothing is announced that did not install.
54
- 5. `gh release create vX.Y.Z --generate-notes`, with `--prerelease` for a dev
57
+ 6. `gh release create vX.Y.Z --generate-notes`, with `--prerelease` for a dev
55
58
  or rc tag.
56
59
  For a final release, also move the `v0` tag that external callers of the
57
60
  reusable workflows track: `git tag -f v0 vX.Y.Z && git push -f origin v0`.
58
61
  Dev and rc tags never move it. This tag alias is the one force-push the
59
62
  repository allows; branches are never force-pushed.
60
- 6. Announce. Discord's `#announcements` gets the release from the GitHub
63
+ 7. Announce. Discord's `#announcements` gets the release from the GitHub
61
64
  webhook on its own (docs/community.md). For a final release, also write
62
65
  the post for X (`@outerloop_sci`) and Bluesky (`@outerloop.science`): one
63
66
  or two sentences on what changed for the reader, the install line, the
@@ -0,0 +1,86 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 880 210" width="880" height="210" role="img" aria-label="One Outerloop attempt: an agent proposes a change, runs the experiment on your GPUs, the kernel re-measures it against the base, judges review the claim, and a pull request opens with a written report. Without a real gain the attempt ends in a report and the next hypothesis.">
2
+ <style>
3
+ svg { --fg: #e4e7eb; --muted: #9aa5b1; --line: #3e4c59; --card: #161b22; --accent: #6ea2ff; --good: #4cc38a; }
4
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; fill: var(--fg); }
5
+ .title { font-size: 15px; font-weight: 600; }
6
+ .sub { font-size: 12px; fill: var(--muted); }
7
+ .node { fill: var(--card); stroke: var(--line); stroke-width: 1.5; }
8
+ .edge { stroke: var(--line); stroke-width: 1.5; fill: none; }
9
+ .back { stroke: var(--line); stroke-width: 1.5; fill: none; stroke-dasharray: 5 5; }
10
+ .head { fill: var(--line); }
11
+ .dot { fill: var(--accent); }
12
+ .score { font-size: 12px; font-variant-numeric: tabular-nums; fill: var(--fg); }
13
+ .ok { fill: var(--good); font-weight: 600; }
14
+ .pr { fill: var(--accent); font-weight: 600; font-size: 12px; }
15
+
16
+ .n1 { animation: lit1 12s infinite; } .n2 { animation: lit2 12s infinite; }
17
+ .n3 { animation: lit3 12s infinite; } .n4 { animation: lit4 12s infinite; }
18
+ .n5 { animation: lit5 12s infinite; }
19
+
20
+ @keyframes lit1 { 0%, 11% { stroke: var(--accent); stroke-width: 2.5; } 13%, 100% { stroke: var(--line); stroke-width: 1.5; } }
21
+ @keyframes lit2 { 0%, 15% { stroke: var(--line); stroke-width: 1.5; } 16%, 31% { stroke: var(--accent); stroke-width: 2.5; } 33%, 100% { stroke: var(--line); stroke-width: 1.5; } }
22
+ @keyframes lit3 { 0%, 35% { stroke: var(--line); stroke-width: 1.5; } 36%, 53% { stroke: var(--accent); stroke-width: 2.5; } 55%, 100% { stroke: var(--line); stroke-width: 1.5; } }
23
+ @keyframes lit4 { 0%, 57% { stroke: var(--line); stroke-width: 1.5; } 58%, 71% { stroke: var(--accent); stroke-width: 2.5; } 73%, 100% { stroke: var(--line); stroke-width: 1.5; } }
24
+ @keyframes lit5 { 0%, 75% { stroke: var(--line); stroke-width: 1.5; } 76%, 96% { stroke: var(--accent); stroke-width: 2.5; } 98%, 100% { stroke: var(--line); stroke-width: 1.5; } }
25
+
26
+ @media (prefers-reduced-motion: reduce) {
27
+ .n1, .n2, .n3, .n4, .n5 { animation: none; }
28
+ }
29
+ </style>
30
+
31
+ <!-- edges between the five steps -->
32
+ <g>
33
+ <line class="edge" x1="172" y1="68" x2="186" y2="68"/><polygon class="head" points="192,68 184,64 184,72"/>
34
+ <line class="edge" x1="344" y1="68" x2="358" y2="68"/><polygon class="head" points="364,68 356,64 356,72"/>
35
+ <line class="edge" x1="516" y1="68" x2="530" y2="68"/><polygon class="head" points="536,68 528,64 528,72"/>
36
+ <line class="edge" x1="688" y1="68" x2="702" y2="68"/><polygon class="head" points="708,68 700,64 700,72"/>
37
+ </g>
38
+
39
+ <!-- the steps -->
40
+ <g>
41
+ <rect class="node n1" x="20" y="36" width="152" height="64" rx="10"/>
42
+ <text class="title" x="96" y="63" text-anchor="middle">Propose</text>
43
+ <text class="sub" x="96" y="83" text-anchor="middle">agent edits the solver</text>
44
+
45
+ <rect class="node n2" x="192" y="36" width="152" height="64" rx="10"/>
46
+ <text class="title" x="268" y="63" text-anchor="middle">Experiment</text>
47
+ <text class="sub" x="268" y="83" text-anchor="middle">jobs on your GPUs</text>
48
+
49
+ <rect class="node n3" x="364" y="36" width="152" height="64" rx="10"/>
50
+ <text class="title" x="440" y="63" text-anchor="middle">Measure</text>
51
+ <text class="sub" x="440" y="83" text-anchor="middle">Outerloop re-measures</text>
52
+
53
+ <rect class="node n4" x="536" y="36" width="152" height="64" rx="10"/>
54
+ <text class="title" x="612" y="63" text-anchor="middle">Review</text>
55
+ <text class="sub" x="612" y="83" text-anchor="middle">judges read the claim</text>
56
+
57
+ <rect class="node n5" x="708" y="36" width="152" height="64" rx="10"/>
58
+ <text class="title" x="784" y="63" text-anchor="middle">Pull request</text>
59
+ <text class="sub" x="784" y="83" text-anchor="middle">with a written report</text>
60
+ </g>
61
+
62
+ <!-- the attempt moving through -->
63
+ <circle class="dot" cx="96" cy="22" r="6">
64
+ <animateTransform attributeName="transform" type="translate" dur="12s" repeatCount="indefinite"
65
+ values="0 0; 0 0; 172 0; 172 0; 344 0; 344 0; 516 0; 516 0; 688 0; 688 0"
66
+ keyTimes="0; 0.10; 0.16; 0.30; 0.36; 0.52; 0.58; 0.70; 0.76; 1"/>
67
+ </circle>
68
+
69
+ <!-- what the measure step reports -->
70
+ <g class="readout" opacity="0">
71
+ <animate attributeName="opacity" dur="12s" repeatCount="indefinite"
72
+ values="0; 0; 1; 1; 0" keyTimes="0; 0.39; 0.42; 0.94; 1"/>
73
+ <text class="score" x="440" y="124" text-anchor="middle">base 9,472 steps → candidate 7,808</text>
74
+ <text class="score ok" x="440" y="142" text-anchor="middle">more than run-to-run noise</text>
75
+ </g>
76
+ <g class="badge" opacity="0">
77
+ <animate attributeName="opacity" dur="12s" repeatCount="indefinite"
78
+ values="0; 0; 1; 1; 0" keyTimes="0; 0.78; 0.81; 0.94; 1"/>
79
+ <text class="pr" x="784" y="124" text-anchor="middle">opened for a human to merge</text>
80
+ </g>
81
+
82
+ <!-- no gain: report and try again -->
83
+ <path class="back" d="M 440 154 L 440 176 L 96 176 L 96 108"/>
84
+ <polygon class="head" points="96,102 92,110 100,110"/>
85
+ <text class="sub" x="268" y="196" text-anchor="middle">no real gain: the report says why, and the next hypothesis starts</text>
86
+ </svg>
@@ -0,0 +1,86 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 880 210" width="880" height="210" role="img" aria-label="One Outerloop attempt: an agent proposes a change, runs the experiment on your GPUs, the kernel re-measures it against the base, judges review the claim, and a pull request opens with a written report. Without a real gain the attempt ends in a report and the next hypothesis.">
2
+ <style>
3
+ svg { --fg: #1f2933; --muted: #616e7c; --line: #c4cdd5; --card: #ffffff; --accent: #3c81f7; --good: #1f8a4c; }
4
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; fill: var(--fg); }
5
+ .title { font-size: 15px; font-weight: 600; }
6
+ .sub { font-size: 12px; fill: var(--muted); }
7
+ .node { fill: var(--card); stroke: var(--line); stroke-width: 1.5; }
8
+ .edge { stroke: var(--line); stroke-width: 1.5; fill: none; }
9
+ .back { stroke: var(--line); stroke-width: 1.5; fill: none; stroke-dasharray: 5 5; }
10
+ .head { fill: var(--line); }
11
+ .dot { fill: var(--accent); }
12
+ .score { font-size: 12px; font-variant-numeric: tabular-nums; fill: var(--fg); }
13
+ .ok { fill: var(--good); font-weight: 600; }
14
+ .pr { fill: var(--accent); font-weight: 600; font-size: 12px; }
15
+
16
+ .n1 { animation: lit1 12s infinite; } .n2 { animation: lit2 12s infinite; }
17
+ .n3 { animation: lit3 12s infinite; } .n4 { animation: lit4 12s infinite; }
18
+ .n5 { animation: lit5 12s infinite; }
19
+
20
+ @keyframes lit1 { 0%, 11% { stroke: var(--accent); stroke-width: 2.5; } 13%, 100% { stroke: var(--line); stroke-width: 1.5; } }
21
+ @keyframes lit2 { 0%, 15% { stroke: var(--line); stroke-width: 1.5; } 16%, 31% { stroke: var(--accent); stroke-width: 2.5; } 33%, 100% { stroke: var(--line); stroke-width: 1.5; } }
22
+ @keyframes lit3 { 0%, 35% { stroke: var(--line); stroke-width: 1.5; } 36%, 53% { stroke: var(--accent); stroke-width: 2.5; } 55%, 100% { stroke: var(--line); stroke-width: 1.5; } }
23
+ @keyframes lit4 { 0%, 57% { stroke: var(--line); stroke-width: 1.5; } 58%, 71% { stroke: var(--accent); stroke-width: 2.5; } 73%, 100% { stroke: var(--line); stroke-width: 1.5; } }
24
+ @keyframes lit5 { 0%, 75% { stroke: var(--line); stroke-width: 1.5; } 76%, 96% { stroke: var(--accent); stroke-width: 2.5; } 98%, 100% { stroke: var(--line); stroke-width: 1.5; } }
25
+
26
+ @media (prefers-reduced-motion: reduce) {
27
+ .n1, .n2, .n3, .n4, .n5 { animation: none; }
28
+ }
29
+ </style>
30
+
31
+ <!-- edges between the five steps -->
32
+ <g>
33
+ <line class="edge" x1="172" y1="68" x2="186" y2="68"/><polygon class="head" points="192,68 184,64 184,72"/>
34
+ <line class="edge" x1="344" y1="68" x2="358" y2="68"/><polygon class="head" points="364,68 356,64 356,72"/>
35
+ <line class="edge" x1="516" y1="68" x2="530" y2="68"/><polygon class="head" points="536,68 528,64 528,72"/>
36
+ <line class="edge" x1="688" y1="68" x2="702" y2="68"/><polygon class="head" points="708,68 700,64 700,72"/>
37
+ </g>
38
+
39
+ <!-- the steps -->
40
+ <g>
41
+ <rect class="node n1" x="20" y="36" width="152" height="64" rx="10"/>
42
+ <text class="title" x="96" y="63" text-anchor="middle">Propose</text>
43
+ <text class="sub" x="96" y="83" text-anchor="middle">agent edits the solver</text>
44
+
45
+ <rect class="node n2" x="192" y="36" width="152" height="64" rx="10"/>
46
+ <text class="title" x="268" y="63" text-anchor="middle">Experiment</text>
47
+ <text class="sub" x="268" y="83" text-anchor="middle">jobs on your GPUs</text>
48
+
49
+ <rect class="node n3" x="364" y="36" width="152" height="64" rx="10"/>
50
+ <text class="title" x="440" y="63" text-anchor="middle">Measure</text>
51
+ <text class="sub" x="440" y="83" text-anchor="middle">Outerloop re-measures</text>
52
+
53
+ <rect class="node n4" x="536" y="36" width="152" height="64" rx="10"/>
54
+ <text class="title" x="612" y="63" text-anchor="middle">Review</text>
55
+ <text class="sub" x="612" y="83" text-anchor="middle">judges read the claim</text>
56
+
57
+ <rect class="node n5" x="708" y="36" width="152" height="64" rx="10"/>
58
+ <text class="title" x="784" y="63" text-anchor="middle">Pull request</text>
59
+ <text class="sub" x="784" y="83" text-anchor="middle">with a written report</text>
60
+ </g>
61
+
62
+ <!-- the attempt moving through -->
63
+ <circle class="dot" cx="96" cy="22" r="6">
64
+ <animateTransform attributeName="transform" type="translate" dur="12s" repeatCount="indefinite"
65
+ values="0 0; 0 0; 172 0; 172 0; 344 0; 344 0; 516 0; 516 0; 688 0; 688 0"
66
+ keyTimes="0; 0.10; 0.16; 0.30; 0.36; 0.52; 0.58; 0.70; 0.76; 1"/>
67
+ </circle>
68
+
69
+ <!-- what the measure step reports -->
70
+ <g class="readout" opacity="0">
71
+ <animate attributeName="opacity" dur="12s" repeatCount="indefinite"
72
+ values="0; 0; 1; 1; 0" keyTimes="0; 0.39; 0.42; 0.94; 1"/>
73
+ <text class="score" x="440" y="124" text-anchor="middle">base 9,472 steps → candidate 7,808</text>
74
+ <text class="score ok" x="440" y="142" text-anchor="middle">more than run-to-run noise</text>
75
+ </g>
76
+ <g class="badge" opacity="0">
77
+ <animate attributeName="opacity" dur="12s" repeatCount="indefinite"
78
+ values="0; 0; 1; 1; 0" keyTimes="0; 0.78; 0.81; 0.94; 1"/>
79
+ <text class="pr" x="784" y="124" text-anchor="middle">opened for a human to merge</text>
80
+ </g>
81
+
82
+ <!-- no gain: report and try again -->
83
+ <path class="back" d="M 440 154 L 440 176 L 96 176 L 96 108"/>
84
+ <polygon class="head" points="96,102 92,110 100,110"/>
85
+ <text class="sub" x="268" y="196" text-anchor="middle">no real gain: the report says why, and the next hypothesis starts</text>
86
+ </svg>
@@ -17,23 +17,27 @@ placed and capped before any TPU contract is accepted.
17
17
 
18
18
  ## What assumes a GPU today
19
19
 
20
- - **Declaration.** `Benchmark.gpus: int (0..8)`; `Measure.gpus`,
21
- `JobSpec.gpus`; the GPU type lives on the operator's per-target lane
20
+ - **Declaration.** `Benchmark.gpus: int (0..8)` per node and
21
+ `Benchmark.nodes: int (1..64)`; `Measure.gpus`/`nodes`, `JobSpec.gpus`/`nodes`;
22
+ `Benchmark.total_gpus` is what one job holds. The GPU type lives on the operator's per-target lane
22
23
  (`OUTERLOOP_GPU_LANES`, `gpu_lanes.py`). Whether evals dispatch depends on
23
24
  `eval_minutes`, not on `gpus`.
24
- - **Metering.** Launches charge minutes × array × gpus / 60; gates charge the
25
- main eval (one when a cached baseline applies, else two) and every suite
26
- sibling pair × walltime × gpus (`syscall.py`). The run meter is
25
+ - **Metering.** Launches charge minutes × array × total GPUs / 60; gates charge
26
+ the main eval (one when a cached baseline applies, else two) and every suite
27
+ sibling pair × walltime × total GPUs (`syscall.py`). The run meter is
27
28
  `stage.gpu_hours_used`; budgets are `gpu_hours_per_run` plus
28
29
  `review_topup.gpu_hours`; `max_concurrent_gpus` paces sweeps.
29
30
  - **Placement.** `JobSpec.to_argv` emits `--gres=gpu:TYPE:N` or
30
- `--gpus-per-node=N`, single node; dispatched evals add `--nv` and size CPUs
31
- and memory per GPU.
31
+ `--gpus-per-node=N`, plus `--nodes=M --ntasks-per-node=1` for a multi-node
32
+ benchmark; dispatched evals add `--nv` and size CPUs and memory per GPU, per
33
+ node. A multi-node eval `srun`s its per-node script once per node
34
+ (uncontained deployments only).
32
35
  - **Operator limits.** `limits.toml` `max_gpus`, counted from one
33
36
  `squeue --me --json` snapshot by parsing `gres/gpu` TRES, attributing jobs to
34
37
  this fleet by run id.
35
- - **Local backend.** `nvidia-smi` detection (or `OUTERLOOP_LOCAL_GPUS`),
36
- `CUDA_VISIBLE_DEVICES` pinning.
38
+ - **Local backend.** `nvidia-smi` detection (or `OUTERLOOP_LOCAL_GPUS`), the
39
+ loop's own `CUDA_VISIBLE_DEVICES` when it is set, `CUDA_VISIBLE_DEVICES`
40
+ pinning.
37
41
  - **Surfaces.** Briefs, wake lines, refusals, `budget.json`
38
42
  (`gpu_hours_remaining`), `outerloop status`, `outerloop limits` and the board
39
43
  carry GPU-named fields.