harness-run 0.4.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 (143) hide show
  1. harness_run-0.4.0/.dockerignore +12 -0
  2. harness_run-0.4.0/.github/workflows/ci.yml +40 -0
  3. harness_run-0.4.0/.github/workflows/publish.yml +104 -0
  4. harness_run-0.4.0/.gitignore +13 -0
  5. harness_run-0.4.0/CHANGELOG.md +50 -0
  6. harness_run-0.4.0/DESIGN.md +932 -0
  7. harness_run-0.4.0/LICENSE +202 -0
  8. harness_run-0.4.0/Makefile +85 -0
  9. harness_run-0.4.0/PKG-INFO +248 -0
  10. harness_run-0.4.0/README.md +216 -0
  11. harness_run-0.4.0/SECURITY.md +27 -0
  12. harness_run-0.4.0/TESTING.md +343 -0
  13. harness_run-0.4.0/dev/Dockerfile +44 -0
  14. harness_run-0.4.0/dev/README.md +53 -0
  15. harness_run-0.4.0/dev/chat.py +354 -0
  16. harness_run-0.4.0/dev/live_interactive_probe.py +210 -0
  17. harness_run-0.4.0/dev/live_limits_probe.py +375 -0
  18. harness_run-0.4.0/dev/live_model_attribution.py +224 -0
  19. harness_run-0.4.0/dev/live_openrouter_probe.py +560 -0
  20. harness_run-0.4.0/dev/live_openrouter_remote_probe.py +653 -0
  21. harness_run-0.4.0/dev/live_resume_probe.py +81 -0
  22. harness_run-0.4.0/dev/live_smoke.py +639 -0
  23. harness_run-0.4.0/dev/live_two_turn_probe.py +92 -0
  24. harness_run-0.4.0/dev/live_usage_probe.py +239 -0
  25. harness_run-0.4.0/dev/openrouter_endpoints.py +153 -0
  26. harness_run-0.4.0/docs/configuration.md +221 -0
  27. harness_run-0.4.0/docs/gcp-setup.md +129 -0
  28. harness_run-0.4.0/docs/getting-started.md +128 -0
  29. harness_run-0.4.0/docs/harnesses-and-models.md +110 -0
  30. harness_run-0.4.0/docs/local-runtime.md +118 -0
  31. harness_run-0.4.0/docs/observability.md +94 -0
  32. harness_run-0.4.0/docs/openrouter.md +259 -0
  33. harness_run-0.4.0/docs/runs-and-sessions.md +206 -0
  34. harness_run-0.4.0/docs/sandbox-runtime.md +169 -0
  35. harness_run-0.4.0/docs/secrets-and-security.md +131 -0
  36. harness_run-0.4.0/docs/structured-output.md +29 -0
  37. harness_run-0.4.0/examples/minimal/README.md +43 -0
  38. harness_run-0.4.0/examples/minimal/agent.py +73 -0
  39. harness_run-0.4.0/examples/sandbox/README.md +37 -0
  40. harness_run-0.4.0/examples/sandbox/deploy_and_run.py +132 -0
  41. harness_run-0.4.0/harness_run/__init__.py +41 -0
  42. harness_run-0.4.0/harness_run/checkpoint/__init__.py +12 -0
  43. harness_run-0.4.0/harness_run/checkpoint/session_store.py +136 -0
  44. harness_run-0.4.0/harness_run/checkpoint/workspace.py +122 -0
  45. harness_run-0.4.0/harness_run/config.py +331 -0
  46. harness_run-0.4.0/harness_run/conformance.py +196 -0
  47. harness_run-0.4.0/harness_run/control.py +278 -0
  48. harness_run-0.4.0/harness_run/events.py +116 -0
  49. harness_run-0.4.0/harness_run/harness/__init__.py +37 -0
  50. harness_run-0.4.0/harness_run/harness/_local_sdk.py +32 -0
  51. harness_run-0.4.0/harness_run/harness/_openrouter_proxy.py +538 -0
  52. harness_run-0.4.0/harness_run/harness/_shared.py +307 -0
  53. harness_run-0.4.0/harness_run/harness/_usage.py +113 -0
  54. harness_run-0.4.0/harness_run/harness/base.py +36 -0
  55. harness_run-0.4.0/harness_run/harness/claude_code.py +1046 -0
  56. harness_run-0.4.0/harness_run/harness/codex.py +1482 -0
  57. harness_run-0.4.0/harness_run/harness/context.py +107 -0
  58. harness_run-0.4.0/harness_run/harness/pricing.py +141 -0
  59. harness_run-0.4.0/harness_run/harness/translate.py +204 -0
  60. harness_run-0.4.0/harness_run/integrations/__init__.py +28 -0
  61. harness_run-0.4.0/harness_run/integrations/git.py +203 -0
  62. harness_run-0.4.0/harness_run/integrations/github.py +17 -0
  63. harness_run-0.4.0/harness_run/ports/__init__.py +20 -0
  64. harness_run-0.4.0/harness_run/ports/blobstore.py +296 -0
  65. harness_run-0.4.0/harness_run/ports/secrets.py +57 -0
  66. harness_run-0.4.0/harness_run/runtime/__init__.py +11 -0
  67. harness_run-0.4.0/harness_run/runtime/_run.py +232 -0
  68. harness_run-0.4.0/harness_run/runtime/base.py +295 -0
  69. harness_run-0.4.0/harness_run/runtime/local.py +616 -0
  70. harness_run-0.4.0/harness_run/runtime/sandbox/__init__.py +17 -0
  71. harness_run-0.4.0/harness_run/runtime/sandbox/_image.py +291 -0
  72. harness_run-0.4.0/harness_run/runtime/sandbox/backend.py +2004 -0
  73. harness_run-0.4.0/harness_run/runtime/sandbox/handoff.py +201 -0
  74. harness_run-0.4.0/harness_run/runtime/sandbox/history.py +149 -0
  75. harness_run-0.4.0/harness_run/runtime/sandbox/model_token.py +80 -0
  76. harness_run-0.4.0/harness_run/runtime/sandbox/project_setup.py +1359 -0
  77. harness_run-0.4.0/harness_run/runtime/sandbox/provider.py +468 -0
  78. harness_run-0.4.0/harness_run/runtime/sandbox/resources.py +292 -0
  79. harness_run-0.4.0/harness_run/runtime/sandbox/roster.py +237 -0
  80. harness_run-0.4.0/harness_run/runtime/sandbox/scoped_gcs.py +288 -0
  81. harness_run-0.4.0/harness_run/runtime/sandbox/stream.py +264 -0
  82. harness_run-0.4.0/harness_run/runtime/sandbox/worker.py +806 -0
  83. harness_run-0.4.0/harness_run/runtime/venv.py +102 -0
  84. harness_run-0.4.0/harness_run/skills.py +106 -0
  85. harness_run-0.4.0/harness_run/spec.py +604 -0
  86. harness_run-0.4.0/harness_run/structured.py +89 -0
  87. harness_run-0.4.0/pyproject.toml +93 -0
  88. harness_run-0.4.0/tests/codex_fakes.py +284 -0
  89. harness_run-0.4.0/tests/conftest.py +59 -0
  90. harness_run-0.4.0/tests/fakes.py +133 -0
  91. harness_run-0.4.0/tests/sandbox_fakes.py +223 -0
  92. harness_run-0.4.0/tests/test_background_tasks.py +664 -0
  93. harness_run-0.4.0/tests/test_blobstore.py +146 -0
  94. harness_run-0.4.0/tests/test_cab_literals.py +35 -0
  95. harness_run-0.4.0/tests/test_checkpoint_events.py +94 -0
  96. harness_run-0.4.0/tests/test_checkpoint_secrets.py +32 -0
  97. harness_run-0.4.0/tests/test_claude_resume.py +99 -0
  98. harness_run-0.4.0/tests/test_client_credentials.py +79 -0
  99. harness_run-0.4.0/tests/test_codex_checkpoint_failures.py +134 -0
  100. harness_run-0.4.0/tests/test_codex_harness.py +1511 -0
  101. harness_run-0.4.0/tests/test_codex_policy.py +28 -0
  102. harness_run-0.4.0/tests/test_config.py +241 -0
  103. harness_run-0.4.0/tests/test_config_secrets.py +61 -0
  104. harness_run-0.4.0/tests/test_config_transport.py +158 -0
  105. harness_run-0.4.0/tests/test_control.py +624 -0
  106. harness_run-0.4.0/tests/test_dev_probe_teardown.py +136 -0
  107. harness_run-0.4.0/tests/test_dispatch_ownership.py +452 -0
  108. harness_run-0.4.0/tests/test_exec.py +264 -0
  109. harness_run-0.4.0/tests/test_handoff.py +117 -0
  110. harness_run-0.4.0/tests/test_harness_conformance.py +101 -0
  111. harness_run-0.4.0/tests/test_harness_options.py +511 -0
  112. harness_run-0.4.0/tests/test_history.py +89 -0
  113. harness_run-0.4.0/tests/test_local_extra.py +84 -0
  114. harness_run-0.4.0/tests/test_local_runtime.py +573 -0
  115. harness_run-0.4.0/tests/test_local_venv.py +140 -0
  116. harness_run-0.4.0/tests/test_openrouter_endpoints.py +7 -0
  117. harness_run-0.4.0/tests/test_openrouter_proxy.py +623 -0
  118. harness_run-0.4.0/tests/test_project_setup.py +598 -0
  119. harness_run-0.4.0/tests/test_provider_templates.py +169 -0
  120. harness_run-0.4.0/tests/test_reattach_config.py +48 -0
  121. harness_run-0.4.0/tests/test_reattach_running_turn.py +428 -0
  122. harness_run-0.4.0/tests/test_repos.py +91 -0
  123. harness_run-0.4.0/tests/test_resources.py +132 -0
  124. harness_run-0.4.0/tests/test_retention.py +45 -0
  125. harness_run-0.4.0/tests/test_roster.py +165 -0
  126. harness_run-0.4.0/tests/test_sandbox_deploy.py +328 -0
  127. harness_run-0.4.0/tests/test_sandbox_runtime.py +867 -0
  128. harness_run-0.4.0/tests/test_scoped_gcs.py +372 -0
  129. harness_run-0.4.0/tests/test_session_cleanup.py +145 -0
  130. harness_run-0.4.0/tests/test_session_store.py +19 -0
  131. harness_run-0.4.0/tests/test_skills.py +55 -0
  132. harness_run-0.4.0/tests/test_spec.py +201 -0
  133. harness_run-0.4.0/tests/test_stderr_capture.py +99 -0
  134. harness_run-0.4.0/tests/test_stream.py +231 -0
  135. harness_run-0.4.0/tests/test_structured.py +46 -0
  136. harness_run-0.4.0/tests/test_token_refresh.py +191 -0
  137. harness_run-0.4.0/tests/test_translate.py +108 -0
  138. harness_run-0.4.0/tests/test_turn_boundaries.py +185 -0
  139. harness_run-0.4.0/tests/test_usage.py +83 -0
  140. harness_run-0.4.0/tests/test_warm_pool.py +260 -0
  141. harness_run-0.4.0/tests/test_worker_metadata_server.py +103 -0
  142. harness_run-0.4.0/tests/test_workspace.py +139 -0
  143. harness_run-0.4.0/tests/test_zero_budget.py +43 -0
@@ -0,0 +1,12 @@
1
+ # Keep the build context small/fast (esp. the multi-hundred-MB .venv) — the dev image
2
+ # COPYs only what it needs from the context anyway.
3
+ .venv
4
+ .git
5
+ **/__pycache__
6
+ *.pyc
7
+ .pytest_cache
8
+ .ruff_cache
9
+ .mypy_cache
10
+ *.egg-info
11
+ dist
12
+ build
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ # All tests are offline unit tests (fake harness, mocked GCP/uv/git-over-network) — CI
4
+ # needs no cloud credentials or API keys and bills nothing beyond the runner. Keep it
5
+ # that way: anything that talks to Vertex/Anthropic belongs in a manually-run script,
6
+ # not under `pytest -q`.
7
+
8
+ on:
9
+ push:
10
+ branches: [main] # PRs are covered by the pull_request trigger — no double runs
11
+ pull_request:
12
+
13
+ concurrency:
14
+ group: ci-${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ test:
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 15
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ python-version: ["3.12", "3.13"] # full requires-python range (>=3.12,<3.14)
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: actions/setup-python@v5
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ - name: Install uv
31
+ uses: astral-sh/setup-uv@v5
32
+ with:
33
+ enable-cache: true
34
+ cache-dependency-glob: pyproject.toml # no lockfile — key the cache off deps
35
+ - name: Install (runtime + dev group)
36
+ run: uv pip install --system -e . --group dev
37
+ - name: Lint
38
+ run: ruff check .
39
+ - name: Test
40
+ run: pytest -q -n auto
@@ -0,0 +1,104 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes a release to PyPI, https://pypi.org/project/harness-run/, through PyPI's Trusted
4
+ # Publishing (OpenID Connect): no API token is stored in this repository. PyPI is configured
5
+ # to trust this exact workflow file in this repository when it runs in the `pypi` GitHub
6
+ # environment; that trust is set up on the PyPI project's Publishing page, not here. TestPyPI
7
+ # trusts the same file in the `testpypi` environment.
8
+ #
9
+ # A release is a tag `vX.Y.Z` on `main`, and X.Y.Z must equal `version` in pyproject.toml
10
+ # (the build job refuses otherwise; see the release checklist at the top of CHANGELOG.md).
11
+ # Plain pushes publish nothing. Running the workflow by hand (workflow_dispatch) publishes the
12
+ # checked-out version to TestPyPI instead, as a dry run of the release path:
13
+ # pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ harness-run==X.Y.Z
14
+ # TestPyPI never accepts the same version twice, so a repeated dry run needs a version bump.
15
+
16
+ on:
17
+ push:
18
+ tags: ["v[0-9]*"]
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ concurrency:
25
+ group: publish-${{ github.ref }}
26
+ cancel-in-progress: false # never cancel an upload half-way
27
+
28
+ jobs:
29
+ build:
30
+ runs-on: ubuntu-latest
31
+ timeout-minutes: 10
32
+ outputs:
33
+ version: ${{ steps.version.outputs.version }}
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: "3.12"
39
+ - name: Install uv
40
+ uses: astral-sh/setup-uv@v5
41
+
42
+ - name: Check the tag against pyproject.toml
43
+ id: version
44
+ run: |
45
+ set -euo pipefail
46
+ declared=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
47
+ tag="${GITHUB_REF_NAME#v}"
48
+ if [[ "$GITHUB_REF_TYPE" == "tag" && "$tag" != "$declared" ]]; then
49
+ echo "::error::tag $GITHUB_REF_NAME does not match pyproject version $declared; bump the version first (CHANGELOG.md, release checklist)"
50
+ exit 1
51
+ fi
52
+ echo "version=$declared" >> "$GITHUB_OUTPUT"
53
+ echo "building harness-run $declared"
54
+
55
+ - name: Build sdist and wheel
56
+ run: |
57
+ set -euo pipefail
58
+ uv build
59
+ uvx twine check --strict dist/*
60
+ ls -l dist/
61
+
62
+ - uses: actions/upload-artifact@v4
63
+ with:
64
+ name: dist
65
+ path: dist/
66
+ if-no-files-found: error
67
+
68
+ publish:
69
+ if: github.ref_type == 'tag'
70
+ needs: build
71
+ runs-on: ubuntu-latest
72
+ timeout-minutes: 10
73
+ environment:
74
+ name: pypi
75
+ url: https://pypi.org/project/harness-run/${{ needs.build.outputs.version }}/
76
+ permissions:
77
+ id-token: write # mint the OIDC token PyPI exchanges for a short-lived upload token
78
+ steps:
79
+ - uses: actions/download-artifact@v4
80
+ with:
81
+ name: dist
82
+ path: dist/
83
+ - name: Upload to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
85
+
86
+ publish-testpypi:
87
+ if: github.event_name == 'workflow_dispatch'
88
+ needs: build
89
+ runs-on: ubuntu-latest
90
+ timeout-minutes: 10
91
+ environment:
92
+ name: testpypi
93
+ url: https://test.pypi.org/project/harness-run/${{ needs.build.outputs.version }}/
94
+ permissions:
95
+ id-token: write
96
+ steps:
97
+ - uses: actions/download-artifact@v4
98
+ with:
99
+ name: dist
100
+ path: dist/
101
+ - name: Upload to TestPyPI
102
+ uses: pypa/gh-action-pypi-publish@release/v1
103
+ with:
104
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+
11
+ # Local agent-tool settings, per developer.
12
+ .claude/
13
+ .mcp.json
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to `harness-run` are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+ Versioning is [SemVer](https://semver.org/)-style with the usual 0.x caveat:
7
+ **minor releases (0.X) may contain backwards-incompatible changes**; patch
8
+ releases (0.X.Y) do not. Every incompatible change is listed under a
9
+ **Backwards-incompatible** heading together with update notes describing how to
10
+ migrate.
11
+
12
+ Releases are git tags (`vX.Y.Z`) on `main`, published to [PyPI](https://pypi.org/project/harness-run/)
13
+ by `.github/workflows/publish.yml` through PyPI's Trusted Publishing; install a specific release with
14
+
15
+ ```
16
+ pip install "harness-run==X.Y.Z"
17
+ ```
18
+
19
+ Release checklist: update this file (move the `Unreleased` section into a new
20
+ version heading with the date), bump `version` in `pyproject.toml`, merge that
21
+ commit to `main` (PR), tag the merge commit `vX.Y.Z` and push the tag. The
22
+ publish workflow refuses a tag whose version differs from `pyproject.toml`; once
23
+ it has uploaded the release, create the GitHub Release for the tag with this
24
+ file's section as the notes.
25
+
26
+ The workflow needs no token: PyPI and TestPyPI trust `publish.yml` from this repository
27
+ running in the `pypi` and `testpypi` GitHub environments (Trusted Publishing, configured on
28
+ the PyPI side under the project's Publishing settings and on the GitHub side under Settings
29
+ → Environments). To rehearse a release, run the workflow by hand from the Actions tab or with
30
+ `gh workflow run publish.yml`: it builds the checked-out version and uploads it to TestPyPI
31
+ only, where it can be checked with
32
+
33
+ ```
34
+ pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "harness-run==X.Y.Z"
35
+ ```
36
+
37
+ TestPyPI never accepts the same version twice, so a second rehearsal needs a version bump.
38
+
39
+ ## 0.4.0 — 2026-09-23
40
+
41
+ First public release.
42
+
43
+ `harness-run` was developed at [Zyte](https://www.zyte.com) as an internal library
44
+ (`remote-agent-toolkit`, versions 0.1.0–0.3.1) and is released here under the Apache-2.0
45
+ license with a new name. It runs coding agents — Claude Code and Codex, with Anthropic, OpenAI,
46
+ Vertex AI and OpenRouter models — locally and in GCP Agent Sandbox through one API: declarative
47
+ `AgentSpec`s, multi-turn sessions with checkpoint/resume, streaming events, structured output,
48
+ skills, MCP servers, repository setup, per-run secrets and usage/cost reporting. The
49
+ [README](README.md) and [docs/](docs/) describe the release; the development history before it
50
+ is in the git log.