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.
- rlm_harness-1.0.0/.claude/rules/handoff.md +55 -0
- rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- rlm_harness-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- rlm_harness-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- rlm_harness-1.0.0/.github/workflows/ci.yml +54 -0
- rlm_harness-1.0.0/.github/workflows/release.yml +52 -0
- rlm_harness-1.0.0/.gitignore +9 -0
- rlm_harness-1.0.0/CHANGELOG.md +775 -0
- rlm_harness-1.0.0/CLAUDE.md +238 -0
- rlm_harness-1.0.0/CODE_OF_CONDUCT.md +85 -0
- rlm_harness-1.0.0/CONTRIBUTING.md +73 -0
- rlm_harness-1.0.0/LICENSE +21 -0
- rlm_harness-1.0.0/PKG-INFO +197 -0
- rlm_harness-1.0.0/README.md +161 -0
- rlm_harness-1.0.0/SECURITY.md +40 -0
- rlm_harness-1.0.0/examples/claude_agent_lm.py +60 -0
- rlm_harness-1.0.0/examples/command_runner.py +105 -0
- rlm_harness-1.0.0/examples/harness_run.py +102 -0
- rlm_harness-1.0.0/examples/harness_serve.py +49 -0
- rlm_harness-1.0.0/examples/mini_run.py +77 -0
- rlm_harness-1.0.0/pyproject.toml +118 -0
- rlm_harness-1.0.0/rlm_harness/README.md +665 -0
- rlm_harness-1.0.0/rlm_harness/__init__.py +146 -0
- rlm_harness-1.0.0/rlm_harness/_retry.py +118 -0
- rlm_harness-1.0.0/rlm_harness/_sandbox_agent.py +209 -0
- rlm_harness-1.0.0/rlm_harness/claude_agent_lm.py +288 -0
- rlm_harness-1.0.0/rlm_harness/config.py +282 -0
- rlm_harness-1.0.0/rlm_harness/container_interpreter.py +498 -0
- rlm_harness-1.0.0/rlm_harness/dataset.py +263 -0
- rlm_harness-1.0.0/rlm_harness/harness_serve.py +54 -0
- rlm_harness-1.0.0/rlm_harness/mcp.py +402 -0
- rlm_harness-1.0.0/rlm_harness/optimize.py +107 -0
- rlm_harness-1.0.0/rlm_harness/py.typed +0 -0
- rlm_harness-1.0.0/rlm_harness/replay.py +85 -0
- rlm_harness-1.0.0/rlm_harness/rubric.py +140 -0
- rlm_harness-1.0.0/rlm_harness/runtime.py +267 -0
- rlm_harness-1.0.0/rlm_harness/sandbox.py +318 -0
- rlm_harness-1.0.0/rlm_harness/serving.py +287 -0
- rlm_harness-1.0.0/rlm_harness/skills.py +170 -0
- rlm_harness-1.0.0/rlm_harness/sub_lm.py +203 -0
- rlm_harness-1.0.0/rlm_harness/task.py +288 -0
- rlm_harness-1.0.0/rlm_harness/testing.py +144 -0
- rlm_harness-1.0.0/rlm_harness/tools/__init__.py +50 -0
- rlm_harness-1.0.0/rlm_harness/tools/command.py +143 -0
- rlm_harness-1.0.0/rlm_harness/tools/fetch.py +178 -0
- rlm_harness-1.0.0/rlm_harness/tools/harness.py +149 -0
- rlm_harness-1.0.0/rlm_harness/tools/model.py +179 -0
- rlm_harness-1.0.0/rlm_harness/tools/search.py +95 -0
- rlm_harness-1.0.0/rlm_harness/tools/validation.py +89 -0
- rlm_harness-1.0.0/rlm_harness/trace.py +380 -0
- rlm_harness-1.0.0/tests/test_claude_agent_lm.py +119 -0
- rlm_harness-1.0.0/tests/test_config.py +150 -0
- rlm_harness-1.0.0/tests/test_container_interpreter.py +301 -0
- rlm_harness-1.0.0/tests/test_contract.py +120 -0
- rlm_harness-1.0.0/tests/test_export_actions.py +90 -0
- rlm_harness-1.0.0/tests/test_harness_tool.py +158 -0
- rlm_harness-1.0.0/tests/test_integration_dspy.py +397 -0
- rlm_harness-1.0.0/tests/test_mcp.py +574 -0
- rlm_harness-1.0.0/tests/test_packaging.py +39 -0
- rlm_harness-1.0.0/tests/test_repl_safety.py +96 -0
- rlm_harness-1.0.0/tests/test_replay_dataset.py +117 -0
- rlm_harness-1.0.0/tests/test_retry.py +193 -0
- rlm_harness-1.0.0/tests/test_rubric.py +93 -0
- rlm_harness-1.0.0/tests/test_run_label_bundle.py +41 -0
- rlm_harness-1.0.0/tests/test_runtime.py +78 -0
- rlm_harness-1.0.0/tests/test_sandbox.py +279 -0
- rlm_harness-1.0.0/tests/test_scripted_interpreter.py +101 -0
- rlm_harness-1.0.0/tests/test_serving.py +377 -0
- rlm_harness-1.0.0/tests/test_skills.py +111 -0
- rlm_harness-1.0.0/tests/test_sub_lm.py +108 -0
- rlm_harness-1.0.0/tests/test_tools.py +668 -0
- rlm_harness-1.0.0/tests/test_trace.py +449 -0
- 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,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
|