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.
- outerloop_science-0.6.0/.claude-plugin/marketplace.json +14 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.pre-commit-config.yaml +1 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CHANGELOG.md +110 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CITATION.cff +2 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CONTRIBUTING.md +13 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/PKG-INFO +30 -6
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/README.md +29 -5
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/RELEASING.md +7 -4
- outerloop_science-0.6.0/docs/assets/loop-dark.svg +86 -0
- outerloop_science-0.6.0/docs/assets/loop.svg +86 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/accelerators.md +13 -9
- outerloop_science-0.6.0/docs/design/forge.md +318 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/lifecycle.md +4 -2
- outerloop_science-0.6.0/docs/design/personal-token.md +268 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/roles.md +8 -9
- outerloop_science-0.6.0/docs/design/trajectory.md +67 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/endpoints.md +9 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/getting-started.md +33 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/index.md +3 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/install.md +91 -9
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/operate.md +4 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/cli.md +42 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/contract.md +16 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/environment.md +73 -5
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reviewer.md +4 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/roadmap.md +10 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/session-capture.md +5 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/storage.md +1 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/examples/review.yml +2 -0
- outerloop_science-0.6.0/plugins/outerloop/.claude-plugin/plugin.json +10 -0
- outerloop_science-0.6.0/plugins/outerloop/.codex-plugin/plugin.json +19 -0
- outerloop_science-0.6.0/plugins/outerloop/skills/contract/SKILL.md +41 -0
- outerloop_science-0.6.0/plugins/outerloop/skills/operate/SKILL.md +52 -0
- outerloop_science-0.6.0/plugins/outerloop/skills/setup/SKILL.md +82 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/pyproject.toml +1 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_deploy.sh +5 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/__init__.py +1 -1
- outerloop_science-0.6.0/src/outerloop/agent_text.py +343 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/attempt.py +455 -118
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/author_overrides.py +11 -7
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/brief.py +3 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/cli.py +313 -12
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/climbboard.py +135 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/compute.py +80 -27
- outerloop_science-0.6.0/src/outerloop/containment/__init__.py +135 -0
- outerloop_science-0.6.0/src/outerloop/containment/macos.sb +18 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/contract.py +22 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/dispatch.py +156 -10
- outerloop_science-0.6.0/src/outerloop/forge.py +253 -0
- outerloop_science-0.6.0/src/outerloop/forge_local.py +1594 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/github.py +132 -107
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/guidance_pack.py +3 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness.py +88 -12
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness_cli.py +32 -5
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hermes_capture.py +20 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/image.py +13 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/inbox.py +61 -25
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/init.py +286 -14
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/intake.py +3 -4
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/launchlog.py +24 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_branch.py +17 -8
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_events.py +26 -15
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/ledger_migrate.py +12 -9
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain.py +15 -7
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain_post_cli.py +1 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/markers.py +20 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/measure.py +79 -6
- outerloop_science-0.6.0/src/outerloop/number_check.py +86 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/operator_limits.py +35 -5
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/orchestrator.py +268 -22
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/posting.py +24 -4
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/progress.py +27 -7
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review.py +15 -12
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_agent.py +61 -6
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_post_cli.py +26 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_summarize_cli.py +26 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/role_runner.py +7 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/session_evidence.py +106 -9
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/status.py +11 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/steward.py +43 -30
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/syscall.py +13 -14
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/syscall_cli.py +57 -16
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/tick.py +200 -84
- outerloop_science-0.6.0/src/outerloop/tool_calls.py +296 -0
- outerloop_science-0.6.0/src/outerloop/trajectory.py +332 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verifier.py +21 -9
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/conftest.py +20 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/README.md +5 -0
- outerloop_science-0.6.0/tests/fixtures/climb-status-legacy.json +24 -0
- outerloop_science-0.6.0/tests/fixtures/session_index_legacy.json +19 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/ledger_fake.py +18 -0
- outerloop_science-0.6.0/tests/test_agent_plugin.py +31 -0
- outerloop_science-0.6.0/tests/test_agent_text.py +177 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_app_permissions.py +33 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_attempt.py +517 -552
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_attempt_review.py +92 -106
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_author_overrides.py +131 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_brief.py +3 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_climbboard.py +198 -80
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_bridge.py +56 -0
- outerloop_science-0.6.0/tests/test_containment.py +180 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract.py +38 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_switches.py +16 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_default_claude_model.py +11 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_dispatch.py +246 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_endpoints.py +58 -1
- outerloop_science-0.6.0/tests/test_forge.py +56 -0
- outerloop_science-0.6.0/tests/test_forge_local.py +249 -0
- outerloop_science-0.6.0/tests/test_forge_local_e2e.py +220 -0
- outerloop_science-0.6.0/tests/test_forge_local_records.py +610 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_github.py +87 -158
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hardening.py +0 -6
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_harness.py +154 -178
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_harness_pins.py +48 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hermes_author.py +7 -1
- outerloop_science-0.6.0/tests/test_identity.py +80 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_inbox.py +50 -89
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_init.py +474 -269
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_install_harness.py +10 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_launchlog.py +8 -3
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_ledger_migrate.py +25 -4
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_local_compute.py +124 -138
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_maintain.py +3 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_measure.py +59 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_messages.py +8 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_end.py +9 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_limits.py +30 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_orchestrator.py +258 -126
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_posting.py +56 -2
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_progress.py +9 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_agent.py +103 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_summarize.py +24 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_session_evidence.py +175 -9
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_start.py +173 -197
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_status.py +36 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_steward.py +1 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_syscall.py +65 -86
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_syscall_cli.py +50 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick.py +622 -542
- outerloop_science-0.6.0/tests/test_tool_calls.py +281 -0
- outerloop_science-0.6.0/tests/test_trajectory.py +222 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verifier.py +16 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_version.py +1 -1
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/uv.lock +122 -122
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.gitignore +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/.python-version +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/CLAUDE.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/LICENSE +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/NOTICE +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/SECURITY.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/containers/README.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/containers/agent-py312.def +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon-dark.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon-light.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/icon.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-apple-touch-icon.png +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-favicon.png +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/assets/outerloop-favicon.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/community.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/concurrency.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/contract.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-environment.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-protocols.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/agent-substrate.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/architecture.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/base-reintegration.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/compute-cloud.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/consolidation.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/dispatcher.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/eval-cache.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/external.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/github-app-auth.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/headline.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/judge-placement.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/meta.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/model-gateway.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/multi-cluster.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/onboarding.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/orchestrator-verify.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/public-surface.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-lines.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-loop-buildout.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/research-loop.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/resident-tick.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/review-placement.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/reviewer-infra.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/role-cli.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/scaling.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/design/session-watcher.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/how-it-works.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/javascripts/figures.js +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/messages.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/inbox.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/reference/syscalls.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/stylesheets/figures.css +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/stylesheets/site.css +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/docs/validation/author-syscalls.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/mkdocs.yml +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/circle-half.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/moon.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/search.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/bi/sun.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/.icons/lab/github.svg +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/main.html +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/overrides/partials/logo.html +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/README.md +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/docs/build.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/docs/hooks.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_bridge.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_claude.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_codex.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/install_hermes.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/requeue_moved_successors.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/setup_branch_protection.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/sweep_git_locks.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_chain.sbatch +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/scripts/tick_resident.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/__main__.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/appauth.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/appmanifest.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_install.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_runtime/pyproject.toml +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/bridge_runtime/uv.lock +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/codex_bridge.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/codex_requirements.toml +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/contract_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/disk.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/endpoint_wait.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/endpoints.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/evalcache.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/gpu_lanes.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harness_pins.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/harnesses.toml +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hermes_install.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/housekeeping.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/hypothesis.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/instance.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/job_names.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/limits.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/maintain_agent_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/panel.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/paths.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/provenance.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/py.typed +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/rebind.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/review_agent_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/roles.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/rolespec.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/runstate.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/style.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_agent.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_agent_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/verify_post_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/src/outerloop/watcher.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fakes.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_legacy.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_missing_model.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/author_route_missing_route.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/base_moved_cc4e5d7.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/default_contract_head.json +0 -0
- {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
- {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
- {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
- {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
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/stdout +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/completed/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/identity.json +0 -0
- {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
- {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
- {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
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/dispatched_pre_gpu_identity/inflight/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/hermes_resume_legacy.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/hermes_sample_20260924.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/launches-before-provenance.jsonl +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/panel_wake_9ca3d7c.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/pre_contract_switches.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/baselines/main@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/brief.txt +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/end-request.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/ended.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-provenance/command.txt +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-provenance/job.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/command.txt +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/exit-code +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/job.sh +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/stdout +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/eval-run/eval-candidate-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69684777d523fe6502ee4ed4d09f98410a56aec/submitted +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/generate.py.txt +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/identity.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/launches.jsonl +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/line.bundle +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/merged.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/open.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pending/owner__repo.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pending/owner__repo@agent-01.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/pr-states.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/queue.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/rebind.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/rc1_v021/sessionless.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/session_cost_legacy.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/fixtures/suite_measurement_legacy.json +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/helpers.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_appauth.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_appmanifest.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_bot_aliases.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_bot_login.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_channel_dir.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_harness.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_hooks.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_codex_host.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_compute.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_contract_names.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_disk.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_endpoint_wait.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_evalcache.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_gpu_lanes.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_hermes_harness.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_housekeeping.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_image.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_import.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_instance.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_intake.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_ledger_events.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_lifecycle_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_limits.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_markers.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_measure_and_decide.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_operator_message.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_packaging.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_panel.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_paths.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_rebind.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_requeue_moved_successors.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_agent_cli.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_hardening.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_review_policy.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_role_runner.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_rolespec.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_runstate.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_sweep_git_locks.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick_chain_successors.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tick_resident.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_tiers.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verify_agent.py +0 -0
- {outerloop_science-0.4.0rc1 → outerloop_science-0.6.0}/tests/test_verify_agent_cli.py +0 -0
- {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
|
+
}
|
|
@@ -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
|
|
|
@@ -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.
|
|
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
|
-
|
|
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.
|
|
64
|
-
|
|
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
|
|
132
|
-
|
|
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
|
-
|
|
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.
|
|
40
|
-
|
|
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
|
|
108
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
21
|
-
`
|
|
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 ×
|
|
25
|
-
main eval (one when a cached baseline applies, else two) and every suite
|
|
26
|
-
sibling pair × walltime ×
|
|
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`,
|
|
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`
|
|
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.
|