rlm-harness 1.0.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 (74) hide show
  1. rlm_harness-1.0.0/.claude/rules/handoff.md +55 -0
  2. rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
  3. rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
  5. rlm_harness-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  6. rlm_harness-1.0.0/.github/workflows/ci.yml +54 -0
  7. rlm_harness-1.0.0/.github/workflows/release.yml +52 -0
  8. rlm_harness-1.0.0/.gitignore +9 -0
  9. rlm_harness-1.0.0/CHANGELOG.md +775 -0
  10. rlm_harness-1.0.0/CLAUDE.md +238 -0
  11. rlm_harness-1.0.0/CODE_OF_CONDUCT.md +85 -0
  12. rlm_harness-1.0.0/CONTRIBUTING.md +73 -0
  13. rlm_harness-1.0.0/LICENSE +21 -0
  14. rlm_harness-1.0.0/PKG-INFO +197 -0
  15. rlm_harness-1.0.0/README.md +161 -0
  16. rlm_harness-1.0.0/SECURITY.md +40 -0
  17. rlm_harness-1.0.0/examples/claude_agent_lm.py +60 -0
  18. rlm_harness-1.0.0/examples/command_runner.py +105 -0
  19. rlm_harness-1.0.0/examples/harness_run.py +102 -0
  20. rlm_harness-1.0.0/examples/harness_serve.py +49 -0
  21. rlm_harness-1.0.0/examples/mini_run.py +77 -0
  22. rlm_harness-1.0.0/pyproject.toml +118 -0
  23. rlm_harness-1.0.0/rlm_harness/README.md +665 -0
  24. rlm_harness-1.0.0/rlm_harness/__init__.py +146 -0
  25. rlm_harness-1.0.0/rlm_harness/_retry.py +118 -0
  26. rlm_harness-1.0.0/rlm_harness/_sandbox_agent.py +209 -0
  27. rlm_harness-1.0.0/rlm_harness/claude_agent_lm.py +288 -0
  28. rlm_harness-1.0.0/rlm_harness/config.py +282 -0
  29. rlm_harness-1.0.0/rlm_harness/container_interpreter.py +498 -0
  30. rlm_harness-1.0.0/rlm_harness/dataset.py +263 -0
  31. rlm_harness-1.0.0/rlm_harness/harness_serve.py +54 -0
  32. rlm_harness-1.0.0/rlm_harness/mcp.py +402 -0
  33. rlm_harness-1.0.0/rlm_harness/optimize.py +107 -0
  34. rlm_harness-1.0.0/rlm_harness/py.typed +0 -0
  35. rlm_harness-1.0.0/rlm_harness/replay.py +85 -0
  36. rlm_harness-1.0.0/rlm_harness/rubric.py +140 -0
  37. rlm_harness-1.0.0/rlm_harness/runtime.py +267 -0
  38. rlm_harness-1.0.0/rlm_harness/sandbox.py +318 -0
  39. rlm_harness-1.0.0/rlm_harness/serving.py +287 -0
  40. rlm_harness-1.0.0/rlm_harness/skills.py +170 -0
  41. rlm_harness-1.0.0/rlm_harness/sub_lm.py +203 -0
  42. rlm_harness-1.0.0/rlm_harness/task.py +288 -0
  43. rlm_harness-1.0.0/rlm_harness/testing.py +144 -0
  44. rlm_harness-1.0.0/rlm_harness/tools/__init__.py +50 -0
  45. rlm_harness-1.0.0/rlm_harness/tools/command.py +143 -0
  46. rlm_harness-1.0.0/rlm_harness/tools/fetch.py +178 -0
  47. rlm_harness-1.0.0/rlm_harness/tools/harness.py +149 -0
  48. rlm_harness-1.0.0/rlm_harness/tools/model.py +179 -0
  49. rlm_harness-1.0.0/rlm_harness/tools/search.py +95 -0
  50. rlm_harness-1.0.0/rlm_harness/tools/validation.py +89 -0
  51. rlm_harness-1.0.0/rlm_harness/trace.py +380 -0
  52. rlm_harness-1.0.0/tests/test_claude_agent_lm.py +119 -0
  53. rlm_harness-1.0.0/tests/test_config.py +150 -0
  54. rlm_harness-1.0.0/tests/test_container_interpreter.py +301 -0
  55. rlm_harness-1.0.0/tests/test_contract.py +120 -0
  56. rlm_harness-1.0.0/tests/test_export_actions.py +90 -0
  57. rlm_harness-1.0.0/tests/test_harness_tool.py +158 -0
  58. rlm_harness-1.0.0/tests/test_integration_dspy.py +397 -0
  59. rlm_harness-1.0.0/tests/test_mcp.py +574 -0
  60. rlm_harness-1.0.0/tests/test_packaging.py +39 -0
  61. rlm_harness-1.0.0/tests/test_repl_safety.py +96 -0
  62. rlm_harness-1.0.0/tests/test_replay_dataset.py +117 -0
  63. rlm_harness-1.0.0/tests/test_retry.py +193 -0
  64. rlm_harness-1.0.0/tests/test_rubric.py +93 -0
  65. rlm_harness-1.0.0/tests/test_run_label_bundle.py +41 -0
  66. rlm_harness-1.0.0/tests/test_runtime.py +78 -0
  67. rlm_harness-1.0.0/tests/test_sandbox.py +279 -0
  68. rlm_harness-1.0.0/tests/test_scripted_interpreter.py +101 -0
  69. rlm_harness-1.0.0/tests/test_serving.py +377 -0
  70. rlm_harness-1.0.0/tests/test_skills.py +111 -0
  71. rlm_harness-1.0.0/tests/test_sub_lm.py +108 -0
  72. rlm_harness-1.0.0/tests/test_tools.py +668 -0
  73. rlm_harness-1.0.0/tests/test_trace.py +449 -0
  74. rlm_harness-1.0.0/uv.lock +2867 -0
@@ -0,0 +1,55 @@
1
+ # Context preservation (read before auto-compacting)
2
+
3
+ `rlm-harness` already routes durable knowledge into its tracked docs — keep using them, and
4
+ when the conversation is about to compact, preserve only what they do NOT already hold:
5
+
6
+ - **Stable invariants** → the **Invariants** section of `CLAUDE.md`.
7
+ - **Resolved decisions / shipped changes** → `CHANGELOG.md` (under the current version).
8
+ - **Open / proposed work** → the issue tracker, or the CHANGELOG's unreleased section.
9
+
10
+ So a handoff summary should carry the *in-flight session state* those files miss. Prioritize,
11
+ in order:
12
+
13
+ 1. **Decisions we agreed on this session** that are not yet in CHANGELOG/CLAUDE — design choices
14
+ ("depth stays 1 — depth>1 recursion is out of scope", "skills are knowledge-only, no script
15
+ exec", "dataset split by tool name, not `kind=='tool'`"), API-shape calls, and the *reason*.
16
+ Promote durable ones into CLAUDE.md (invariant) or CHANGELOG.md (change) before they fade.
17
+ 2. **Files / symbols changed**, as `path:symbol` one-liners on the *final* shape — e.g.
18
+ `sub_lm.py:_InterceptedSubLM.__call__ — records the escalation input on the sub_call event`,
19
+ `dataset.py:export_actions — per-action (planner/tool/sub) records with run reward`. Drop
20
+ diffs and intermediate revisions.
21
+ 3. **Current status.** What passes `uv run pytest` (and the count), what is broken, last command
22
+ run + result. One paragraph.
23
+ 4. **Open suggestions / TODOs** not yet tracked — mark each `proposed`,
24
+ `accepted-not-done`, or `rejected`, then move the durable ones into the issue tracker.
25
+ 5. **In-flight consumer signal.** What the downstream consumer surfaced in the current
26
+ work and what it needs — the dogfooding driver.
27
+ 6. **In-flight user intent + acceptance criteria** for this session. Without it a resumed
28
+ session drifts.
29
+
30
+ **Do NOT preserve** (reconstructable / already durable):
31
+
32
+ - Anything already in `CLAUDE.md`, `CHANGELOG.md`, `README.md`, or `pyproject.toml`.
33
+ - Tool-call transcripts, `grep` output, file listings, full file contents readable from disk.
34
+ - Step-by-step exploration narration; speculative reasoning that led to no decision.
35
+
36
+ **Format for a handoff summary** (use when compaction is imminent or the user asks for a recap):
37
+
38
+ ```
39
+ ## Session state
40
+ - Goal: <one sentence>
41
+ - Consumer driving it: <the downstream consumer | none>
42
+ - Status: <what passes pytest, what doesn't, last command + result>
43
+
44
+ ## Decisions
45
+ - <decision> — <why> (→ promote to CLAUDE.md invariant / CHANGELOG.md)
46
+
47
+ ## Changed
48
+ - <path:symbol> — <what & why>
49
+
50
+ ## Open
51
+ - [proposed|accepted-not-done|rejected] <item> (→ issue tracker if durable)
52
+ ```
53
+
54
+ Keep it under ~40 lines. If something fits one of the three tracked docs, put it THERE instead
55
+ of in the summary.
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a defect in rlm-harness
4
+ labels: bug
5
+ ---
6
+
7
+ **What happened**
8
+
9
+ A clear description of the bug.
10
+
11
+ **Reproduction**
12
+
13
+ Minimal steps or a code snippet (include the `RLMTask` declaration if relevant).
14
+
15
+ **Expected**
16
+
17
+ What you expected instead.
18
+
19
+ **Environment**
20
+
21
+ - rlm-harness version / commit:
22
+ - Python version:
23
+ - Interpreter (sandbox `pyodide`/`deno`, or `local`):
24
+
25
+ **Notes**
26
+
27
+ Trace excerpts, stack traces, or logs — redact anything sensitive.
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/qazbnm456/rlm-harness/blob/main/SECURITY.md
5
+ about: Report security issues privately per SECURITY.md — do not open a public issue.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: Feature request / reusable gap
3
+ about: Propose an improvement, or a generic gap the kit should absorb
4
+ labels: enhancement
5
+ ---
6
+
7
+ **The gap or need**
8
+
9
+ What's missing or awkward. If a downstream consumer surfaced it, describe the friction
10
+ generically — no consumer-specific names or values, per the vendor-neutral rule.
11
+
12
+ **Is it generic?**
13
+
14
+ Could this be a reusable mechanic promoted into the kit via the base/wrap split (a generic
15
+ base + guard + factory here; the provider + tracing in the consumer)? Or is it
16
+ consumer-specific (and therefore belongs in the consumer)?
17
+
18
+ **Proposed shape**
19
+
20
+ An API sketch, or which module it would live in.
21
+
22
+ **Alternatives considered**
@@ -0,0 +1,12 @@
1
+ ## What & why
2
+
3
+ <!-- What does this change, and why? Reference any issue it closes, e.g. "Closes #12". -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `uv run --group dev python -m pytest` is green
8
+ - [ ] `uvx ruff check .` is clean
9
+ - [ ] New behavior has a test
10
+ - [ ] No new top-level `dspy` import in a dspy-free module (`config` / `_retry` / `sandbox` / `tools` / `trace` / `skills` / `replay` / `dataset`)
11
+ - [ ] The `rlm-harness/trace/v1` trace is unchanged, or the change is additive (a new optional field) — `tests/test_contract.py` still green
12
+ - [ ] The public surface stays vendor-neutral (no specific downstream project names or values)
@@ -0,0 +1,54 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # Least privilege: this workflow only checks out code and runs tests/lint — it never writes. Specifying
9
+ # `permissions:` also drops every unlisted scope to `none`, so a compromised dep/action on an untrusted
10
+ # fork PR can't use the token to push, tag, or open issues. The third-party setup-uv action is SHA-pinned
11
+ # (a repointed tag could inject code that runs with the token); GitHub-owned checkout stays on a major tag.
12
+ # CI needs no live model, no vLLM, no network, no Deno: the dspy-bearing tests use a DummyLM or skip when
13
+ # dspy is absent.
14
+ permissions:
15
+ contents: read
16
+
17
+ concurrency:
18
+ group: ci-${{ github.ref }}
19
+ cancel-in-progress: true
20
+
21
+ jobs:
22
+ test:
23
+ name: test (py${{ matrix.python-version }})
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ python-version: ["3.11", "3.12", "3.13"]
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+ enable-cache: true
36
+ - name: Run tests
37
+ # --extra mcp so the MCP-client tests run (they spawn a stdio MCP subprocess) rather than skip
38
+ run: uv run --group dev --extra mcp python -m pytest -q
39
+
40
+ lint:
41
+ name: ruff
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - name: Install uv
46
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
47
+ with:
48
+ enable-cache: true
49
+ - name: Lint
50
+ # PINNED on purpose. `uvx ruff` resolves the latest release at run time, and ruff's DEFAULT
51
+ # rule set is not a stable contract — 0.16 expanded it far past the pycodestyle/pyflakes
52
+ # baseline and turned this job red overnight with no code change. Bump it deliberately, with
53
+ # the resulting fixes in the same commit, rather than letting a release do it for you.
54
+ run: uvx ruff@0.16.0 check .
@@ -0,0 +1,52 @@
1
+ name: Release
2
+
3
+ # Publish to PyPI via Trusted Publishing (OIDC) — NO API token. This is INERT until a
4
+ # GitHub Release is published, and requires one-time setup before the first release:
5
+ # 1. On PyPI, add a Trusted Publisher for project `rlm-harness`:
6
+ # owner = qazbnm456, repo = rlm-harness, workflow = release.yml, environment = pypi
7
+ # 2. In this repo's settings, create an environment named `pypi`.
8
+ # Then publishing a GitHub Release (from a `vX.Y.Z` tag) builds + uploads automatically.
9
+ # Supply-chain: the two third-party actions are SHA-pinned — setup-uv, and (highest blast radius, it
10
+ # uploads to PyPI) pypi-publish. Bump a SHA and its trailing version comment together. GitHub-owned
11
+ # checkout/*-artifact stay on major tags.
12
+
13
+ on:
14
+ release:
15
+ types: [published]
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
27
+ - name: Build sdist + wheel
28
+ run: uv build
29
+ - uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish:
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ # Fork guard. `release: published` is inherited by every fork, so a fork cutting its own release
38
+ # would fire this job and ask PyPI to publish `rlm-harness` over OIDC. The Trusted Publisher binding
39
+ # (owner+repo+workflow+environment) would reject it, but that is a rejected publish attempt against
40
+ # OUR project, plus a probe surface and a confusing red run in someone else's repo. `build` above is
41
+ # deliberately NOT guarded — it only builds an artifact, and a fork verifying its own build is fine.
42
+ if: github.repository == 'qazbnm456/rlm-harness'
43
+ environment: pypi
44
+ permissions:
45
+ id-token: write # OIDC token for PyPI Trusted Publishing
46
+ steps:
47
+ - uses: actions/download-artifact@v4
48
+ with:
49
+ name: dist
50
+ path: dist/
51
+ - name: Publish to PyPI
52
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .pytest_cache/
5
+ *.egg-info/
6
+ .env
7
+ dist/
8
+ build/
9
+ traces/