crucible-rl 0.1.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.
- crucible_rl-0.1.0/.gitattributes +4 -0
- crucible_rl-0.1.0/.github/CODEOWNERS +3 -0
- crucible_rl-0.1.0/.github/workflows/ci.yml +26 -0
- crucible_rl-0.1.0/.gitignore +25 -0
- crucible_rl-0.1.0/CONTRIBUTING.md +39 -0
- crucible_rl-0.1.0/CONVENTIONS.md +37 -0
- crucible_rl-0.1.0/LICENSE +20 -0
- crucible_rl-0.1.0/PKG-INFO +258 -0
- crucible_rl-0.1.0/README.md +225 -0
- crucible_rl-0.1.0/ROADMAP.md +116 -0
- crucible_rl-0.1.0/crucible/__init__.py +43 -0
- crucible_rl-0.1.0/crucible/cli.py +83 -0
- crucible_rl-0.1.0/crucible/env.py +71 -0
- crucible_rl-0.1.0/crucible/envs/__init__.py +22 -0
- crucible_rl-0.1.0/crucible/envs/code.py +82 -0
- crucible_rl-0.1.0/crucible/envs/command.py +79 -0
- crucible_rl-0.1.0/crucible/envs/guess.py +71 -0
- crucible_rl-0.1.0/crucible/envs/http.py +75 -0
- crucible_rl-0.1.0/crucible/envs/sql.py +91 -0
- crucible_rl-0.1.0/crucible/envs/terminal.py +91 -0
- crucible_rl-0.1.0/crucible/export.py +75 -0
- crucible_rl-0.1.0/crucible/integrations/__init__.py +7 -0
- crucible_rl-0.1.0/crucible/integrations/trl.py +71 -0
- crucible_rl-0.1.0/crucible/integrations/verifiers.py +53 -0
- crucible_rl-0.1.0/crucible/registry.py +46 -0
- crucible_rl-0.1.0/crucible/reward.py +59 -0
- crucible_rl-0.1.0/crucible/rollout.py +144 -0
- crucible_rl-0.1.0/crucible/sandbox.py +204 -0
- crucible_rl-0.1.0/crucible/trajectory.py +107 -0
- crucible_rl-0.1.0/docs/ARCHITECTURE.md +282 -0
- crucible_rl-0.1.0/docs/BACKLOG.md +205 -0
- crucible_rl-0.1.0/docs/VISION.md +100 -0
- crucible_rl-0.1.0/docs/assets/grpo_sql.png +0 -0
- crucible_rl-0.1.0/docs/assets/grpo_suite.png +0 -0
- crucible_rl-0.1.0/docs/assets/loop.svg +60 -0
- crucible_rl-0.1.0/docs/assets/xmodal.png +0 -0
- crucible_rl-0.1.0/examples/__init__.py +1 -0
- crucible_rl-0.1.0/examples/agents.py +48 -0
- crucible_rl-0.1.0/examples/demo.py +92 -0
- crucible_rl-0.1.0/examples/learn.py +102 -0
- crucible_rl-0.1.0/examples/results/README.md +111 -0
- crucible_rl-0.1.0/examples/results/grpo_sql_rewards.json +29 -0
- crucible_rl-0.1.0/examples/results/grpo_suite.json +287 -0
- crucible_rl-0.1.0/examples/results/plot_grpo.py +82 -0
- crucible_rl-0.1.0/examples/results/plot_grpo_suite.py +89 -0
- crucible_rl-0.1.0/examples/results/plot_xmodal.py +89 -0
- crucible_rl-0.1.0/examples/results/xmodal.json +212 -0
- crucible_rl-0.1.0/examples/train_grpo.py +258 -0
- crucible_rl-0.1.0/examples/train_grpo_suite.py +186 -0
- crucible_rl-0.1.0/examples/train_xmodal.py +231 -0
- crucible_rl-0.1.0/pyproject.toml +52 -0
- crucible_rl-0.1.0/space/README.md +39 -0
- crucible_rl-0.1.0/space/app.py +114 -0
- crucible_rl-0.1.0/space/requirements.txt +2 -0
- crucible_rl-0.1.0/tests/test_cli.py +98 -0
- crucible_rl-0.1.0/tests/test_code_env.py +78 -0
- crucible_rl-0.1.0/tests/test_command_env.py +54 -0
- crucible_rl-0.1.0/tests/test_core.py +143 -0
- crucible_rl-0.1.0/tests/test_docker_sandbox.py +37 -0
- crucible_rl-0.1.0/tests/test_envs.py +130 -0
- crucible_rl-0.1.0/tests/test_export.py +59 -0
- crucible_rl-0.1.0/tests/test_http_env.py +55 -0
- crucible_rl-0.1.0/tests/test_learning.py +33 -0
- crucible_rl-0.1.0/tests/test_persistence.py +80 -0
- crucible_rl-0.1.0/tests/test_pytest_repo.py +56 -0
- crucible_rl-0.1.0/tests/test_registry.py +38 -0
- crucible_rl-0.1.0/tests/test_reward.py +83 -0
- crucible_rl-0.1.0/tests/test_sandbox.py +97 -0
- crucible_rl-0.1.0/tests/test_terminal_env.py +68 -0
- crucible_rl-0.1.0/tests/test_train_grpo.py +68 -0
- crucible_rl-0.1.0/tests/test_train_grpo_suite.py +47 -0
- crucible_rl-0.1.0/tests/test_train_xmodal.py +59 -0
- crucible_rl-0.1.0/tests/test_trl_integration.py +43 -0
- crucible_rl-0.1.0/tests/test_verifiers_integration.py +35 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
|
|
21
|
+
- name: Install
|
|
22
|
+
run: pip install -e ".[dev]"
|
|
23
|
+
|
|
24
|
+
- name: Test (coverage gate >= 90%)
|
|
25
|
+
# pyproject addopts already enforces --cov=crucible --cov-fail-under=90.
|
|
26
|
+
run: pytest
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
|
|
11
|
+
# Coverage
|
|
12
|
+
.coverage
|
|
13
|
+
htmlcov/
|
|
14
|
+
coverage.xml
|
|
15
|
+
|
|
16
|
+
# Local trajectories / runs (don't commit captured episodes)
|
|
17
|
+
/runs/
|
|
18
|
+
/runtime/
|
|
19
|
+
*.trajectory.json
|
|
20
|
+
|
|
21
|
+
# Editor / OS
|
|
22
|
+
.DS_Store
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
*~
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Contributing to Crucible
|
|
2
|
+
|
|
3
|
+
Crucible is open source under the [MIT License](LICENSE) — fork it, build on it, ship
|
|
4
|
+
your own environments. Contributions back to this repository are welcome, with one
|
|
5
|
+
governing rule.
|
|
6
|
+
|
|
7
|
+
## Every merge needs a maintainer +1
|
|
8
|
+
|
|
9
|
+
- `master` is protected — no direct pushes.
|
|
10
|
+
- Propose changes as a pull request from a fork or branch.
|
|
11
|
+
- [`.github/CODEOWNERS`](.github/CODEOWNERS) routes every path to the maintainer
|
|
12
|
+
(@nadeauglenn1-max), so with branch protection set to *require review from Code
|
|
13
|
+
Owners*, approval is enforced by the repo, not just by convention.
|
|
14
|
+
- The maintainer has final say on what merges.
|
|
15
|
+
|
|
16
|
+
## The bar (same as every change here)
|
|
17
|
+
|
|
18
|
+
1. **Tests ship with the change**, and coverage stays **≥ 90%** (`pytest` enforces
|
|
19
|
+
it; CI runs the gate on Python 3.11–3.13).
|
|
20
|
+
2. **Docs move with the code** — update the README / `docs/` in the *same* PR that
|
|
21
|
+
changes behavior. New feature ⇒ its "how" in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
|
|
22
|
+
or a backlog entry in [`docs/BACKLOG.md`](docs/BACKLOG.md).
|
|
23
|
+
3. **The core stays zero-dependency.** Environments and agents may add dependencies;
|
|
24
|
+
`crucible/` core (env, trajectory, rollout, cli) imports only the standard library.
|
|
25
|
+
4. **Honor the determinism contract.** An environment must be a pure function of its
|
|
26
|
+
seed and actions, or `replay` will (correctly) fail it.
|
|
27
|
+
5. **Stay inside the boundary.** Crucible is training/eval infrastructure, not runtime
|
|
28
|
+
agent-accountability — see [`docs/VISION.md`](docs/VISION.md) §5.
|
|
29
|
+
|
|
30
|
+
## Getting started
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e ".[dev]"
|
|
34
|
+
pytest
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
New environments are the most valuable contribution — see the recipe in
|
|
38
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) §7. By contributing, you agree your
|
|
39
|
+
contribution is provided under the project's MIT License.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Crucible — Conventions
|
|
2
|
+
|
|
3
|
+
Standing conventions apply (reuse over rebuild, fix-don't-flag, docs-never-lag-code,
|
|
4
|
+
no-MVP production bar, clean-room provenance, tests ship with the change).
|
|
5
|
+
Project-specific notes:
|
|
6
|
+
|
|
7
|
+
## Core stays tiny and dependency-free
|
|
8
|
+
|
|
9
|
+
The `crucible` core (`env`, `trajectory`, `rollout`, `replay`) imports only the
|
|
10
|
+
Python standard library. Environments and agents may pull dependencies; the core
|
|
11
|
+
may not. Adoption is a feature, and a zero-dependency core is how you get it.
|
|
12
|
+
|
|
13
|
+
## The determinism contract is law
|
|
14
|
+
|
|
15
|
+
`reset(seed)` fully determines an episode. Same seed + same actions ⇒ same
|
|
16
|
+
observations, rewards, and digests. `replay` verifies this and **reports mismatches
|
|
17
|
+
loudly** — a non-reproducible environment is a bug we surface, never one we hide.
|
|
18
|
+
|
|
19
|
+
## Provenance boundary (read `docs/VISION.md` §5)
|
|
20
|
+
|
|
21
|
+
Crucible is training/eval infrastructure. Reward = **programmatic task-success
|
|
22
|
+
checking**. Do **not** drift into runtime agent-accountability, tamper-evident
|
|
23
|
+
trust, or governance — that is a different field and the author's separate IP lives
|
|
24
|
+
there. If a design starts to look like "prove what a deployed agent did," stop.
|
|
25
|
+
|
|
26
|
+
## Quality gates
|
|
27
|
+
|
|
28
|
+
- **Coverage ≥ 90%** on the core + envs, enforced in CI; tests ship with the code.
|
|
29
|
+
- Deterministic tests only — no flaky sleeps; drive time/seeds explicitly.
|
|
30
|
+
- Docs move with the code (README, `docs/VISION.md`) in the same change.
|
|
31
|
+
|
|
32
|
+
## Provenance
|
|
33
|
+
|
|
34
|
+
Clean-room: personal account and environment only, its own history, no code from
|
|
35
|
+
the author's other projects. Licensed **MIT**; public. Contributions merge only with
|
|
36
|
+
green CI plus a maintainer +1 (CODEOWNERS + branch protection) — see
|
|
37
|
+
[`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Glenn Nadeau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crucible-rl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn any real software into a trainable, gradable, replayable RL environment for AI agents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/nadeauglenn1-max/crucible
|
|
6
|
+
Project-URL: Repository, https://github.com/nadeauglenn1-max/crucible
|
|
7
|
+
Project-URL: Issues, https://github.com/nadeauglenn1-max/crucible/issues
|
|
8
|
+
Author: Glenn Nadeau
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,environments,evaluation,grpo,gymnasium,llm,reinforcement-learning,rl,rlvr,training
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
26
|
+
Provides-Extra: train
|
|
27
|
+
Requires-Dist: accelerate>=0.30; extra == 'train'
|
|
28
|
+
Requires-Dist: datasets>=2.19; extra == 'train'
|
|
29
|
+
Requires-Dist: peft>=0.11; extra == 'train'
|
|
30
|
+
Requires-Dist: transformers>=4.44; extra == 'train'
|
|
31
|
+
Requires-Dist: trl>=0.15; extra == 'train'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Crucible
|
|
35
|
+
|
|
36
|
+
> **Crucible** — both the vessel that contains and the trial that transforms, which is
|
|
37
|
+
> exactly what an environment does to an agent.
|
|
38
|
+
|
|
39
|
+
**Crucible turns any real software into a trainable, gradable world for AI agents.**
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
Wrap a CLI, a database, a codebase, or an API in a few lines and it becomes an
|
|
44
|
+
*environment*: an agent can be run through it, scored on real outcomes, and — the
|
|
45
|
+
part nobody else has — its whole episode **replayed deterministically**, so every run
|
|
46
|
+
is reproducible and every reward is auditable.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from crucible import rollout, replay
|
|
50
|
+
|
|
51
|
+
traj = rollout(my_env, my_agent, seed=0) # run the agent, record the episode
|
|
52
|
+
report = replay(fresh_env, traj) # re-run and verify it byte-for-byte
|
|
53
|
+
assert report.ok
|
|
54
|
+
traj.save("episode.trajectory.json") # the artifact leaves memory
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Why this exists
|
|
58
|
+
|
|
59
|
+
The frontier of AI moved off pre-training. Models now improve by **doing** —
|
|
60
|
+
reinforcement learning in environments — and the field agrees on the bottleneck:
|
|
61
|
+
*"RL environments are the key bottleneck to the next wave of AI progress, but big
|
|
62
|
+
labs are locking them down."* Environments are the **training data of 2026**, and
|
|
63
|
+
there is no open, easy way to *make* them. The open ecosystem has a hub (Prime
|
|
64
|
+
Intellect) and a training stack (TRL, verifiers, prime-rl) — it does not have a great
|
|
65
|
+
open **authoring layer**. That's the seam Crucible fills. The full argument is in
|
|
66
|
+
[`docs/VISION.md`](docs/VISION.md).
|
|
67
|
+
|
|
68
|
+
## It actually trains a model
|
|
69
|
+
|
|
70
|
+
Not a toy: a `SQLTaskEnv` used *directly* as a GRPO reward — no labels, no hand-written
|
|
71
|
+
reward code — took `Qwen2.5-0.5B-Instruct` from **5% → 100%** on a real SQL task in 80
|
|
72
|
+
steps on a single laptop GPU. The model discovered the query itself, guided only by the
|
|
73
|
+
environment.
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
And it's **not one lucky task** — a fresh model trained on four *distinct* SQL skills
|
|
78
|
+
improved on every one (subquery, `SUM`, `HAVING`, `AVG`). The method trains, not the
|
|
79
|
+
task.
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
And **not just SQL** — the identical loop trains *different kinds of agents*: a **shell**
|
|
84
|
+
agent (`CommandEnv`, 70→100%) and a **coding** agent graded by *really running its code*
|
|
85
|
+
(`CodeTaskEnv`, 55→85%), alongside a database agent. Only the environment changes. Full
|
|
86
|
+
runs + how to reproduce: [`examples/results/`](examples/results/README.md).
|
|
87
|
+
|
|
88
|
+

|
|
89
|
+
|
|
90
|
+
## Install
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install crucible-rl # the zero-dependency core, Python 3.11+
|
|
94
|
+
pip install "crucible-rl[train]" # + the RL stack, to reproduce the GRPO run
|
|
95
|
+
pip install -e ".[dev]" # or hack on it from a clone
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Quickstart (60 seconds)
|
|
99
|
+
|
|
100
|
+
Run the built-in demo — three real worlds, each forged and replayed:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python -m examples.demo
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
=== CodeTaskEnv - fix the bug so the test goes green (the reward writes itself) ===
|
|
108
|
+
steps: 2 total reward: +0.90 replay: reproduced OK
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Inspect a saved episode from the terminal:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
crucible show episode.trajectory.json # summary + integrity check
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Core concepts
|
|
118
|
+
|
|
119
|
+
Three nouns, two verbs — the whole core is ~180 lines and imports only the standard
|
|
120
|
+
library.
|
|
121
|
+
|
|
122
|
+
| Piece | What it is |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| **`Environment`** | Real software wrapped with `reset(seed)` / `step(action)` |
|
|
125
|
+
| **`Agent`** | Anything with `act(observation) -> action` (scripted, search, an LLM) |
|
|
126
|
+
| **`Trajectory`** | The replayable episode record (seed, observations, actions, rewards) |
|
|
127
|
+
| **`rollout`** | Drives an agent through an environment and records a Trajectory |
|
|
128
|
+
| **`replay`** | Re-runs a Trajectory against a fresh environment and verifies it |
|
|
129
|
+
|
|
130
|
+
How each of these works internally — the rollout loop, the replay verifier, the
|
|
131
|
+
determinism contract, digests, the on-disk format — is documented to junior-dev
|
|
132
|
+
detail in **[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)**.
|
|
133
|
+
|
|
134
|
+
## Write your own environment
|
|
135
|
+
|
|
136
|
+
Wrap software you already have; implement two methods and (optionally) a digest:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from crucible.env import Environment, StepResult
|
|
140
|
+
|
|
141
|
+
class ReverseStringEnv(Environment):
|
|
142
|
+
def __init__(self, target: str):
|
|
143
|
+
self.target = target
|
|
144
|
+
def reset(self, seed: int):
|
|
145
|
+
return {"task": f"reverse: {self.target!r}"}
|
|
146
|
+
def step(self, action):
|
|
147
|
+
correct = str(action) == self.target[::-1]
|
|
148
|
+
return StepResult(
|
|
149
|
+
observation={"you_said": str(action)},
|
|
150
|
+
reward=1.0 if correct else -0.1,
|
|
151
|
+
done=correct,
|
|
152
|
+
info={"correct": correct},
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The rules that make an environment *replayable* (determinism, JSON-serializable
|
|
157
|
+
observations, verifiable reward, digests) and a full worked example are in
|
|
158
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) §7.
|
|
159
|
+
|
|
160
|
+
## The example environments (`crucible/envs/`)
|
|
161
|
+
|
|
162
|
+
| Env | Shows |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `GuessEnv` | A fully deterministic game — the clean proof that replay reproduces an episode exactly |
|
|
165
|
+
| `SQLTaskEnv` | Wrapping **real SQLite** — reward is programmatic and verifiable (run the query, compare the rows) |
|
|
166
|
+
| `CodeTaskEnv` | The SWE-agent shape — **the test suite is the reward function** (edit files, grader runs, green is the reward) |
|
|
167
|
+
| `CommandEnv` | Wrap any **command-line tool** — the agent emits a command, reward is exit-0 + stdout match (sandboxed, registerable) |
|
|
168
|
+
| `TerminalEnv` | A **stateful shell session** — commands accumulate state across steps (mkdir here, write there); reward is a goal over the workdir |
|
|
169
|
+
| `HttpTaskEnv` | Wrap a **recorded HTTP service** (VCR/cassette) — the agent finds the right request; deterministic and registerable |
|
|
170
|
+
|
|
171
|
+
## The CLI
|
|
172
|
+
|
|
173
|
+
- `crucible show <file>` — summarize a saved episode (env, seed, steps, reward,
|
|
174
|
+
fingerprint) and integrity-check it.
|
|
175
|
+
- `crucible replay <file>` — rebuild the environment from the registry and **re-run**
|
|
176
|
+
the episode, confirming it reproduces (or printing the mismatches). Works for
|
|
177
|
+
registered environments; see [ARCHITECTURE §6c](docs/ARCHITECTURE.md).
|
|
178
|
+
|
|
179
|
+
## Project layout
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
crucible/ the zero-dependency core + example environments
|
|
183
|
+
env.py the Environment contract (reset/step, determinism, digest)
|
|
184
|
+
trajectory.py the replayable record (JSON, versioned save/load, fingerprint)
|
|
185
|
+
rollout.py rollout() records; replay() re-runs and verifies
|
|
186
|
+
registry.py register/make envs by name (powers `crucible replay`)
|
|
187
|
+
reward.py Rubric — partial-credit rewards from weighted checks
|
|
188
|
+
sandbox.py run a grader/command in a subprocess (safe for untrusted code)
|
|
189
|
+
export.py flatten trajectories to {prompt, completion, reward} / JSONL
|
|
190
|
+
cli.py the `crucible` command
|
|
191
|
+
envs/ Guess, SQLTask, CodeTask, Command, Terminal, HttpTask
|
|
192
|
+
examples/ demo, agents, and the GRPO training runs + results (not packaged)
|
|
193
|
+
tests/ the suite (100% coverage, enforced in CI)
|
|
194
|
+
docs/ VISION (why), ARCHITECTURE (how), BACKLOG (what's next)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pip install -e ".[dev]"
|
|
201
|
+
pytest # runs the suite; pyproject enforces --cov-fail-under=90
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
CI (`.github/workflows/ci.yml`) runs the same gate on Python 3.11–3.13. Every change
|
|
205
|
+
ships with tests and moves the docs in the same commit (see
|
|
206
|
+
[`CONVENTIONS.md`](CONVENTIONS.md)).
|
|
207
|
+
|
|
208
|
+
## Status & roadmap
|
|
209
|
+
|
|
210
|
+
**V1 (the MVP) is complete**, and the repo is **public under MIT** with tests, CI,
|
|
211
|
+
and a code-owner +1 required to merge. Author → run → grade → replay → persist, as a
|
|
212
|
+
real tool, on one code path, 100% coverage. Where it goes from here — the three-phase
|
|
213
|
+
direction — is in **[`ROADMAP.md`](ROADMAP.md)**; the per-item "how to build it" detail
|
|
214
|
+
is in **[`docs/BACKLOG.md`](docs/BACKLOG.md)**. Progress at a glance:
|
|
215
|
+
|
|
216
|
+
**Built**
|
|
217
|
+
|
|
218
|
+
- [x] Core — `Environment` contract, `Trajectory`, `rollout`, `replay`
|
|
219
|
+
- [x] Deterministic replay that verifies the whole episode (observations, rewards, digests)
|
|
220
|
+
- [x] Trajectory persistence (versioned format) + `crucible show` / `crucible replay` CLI
|
|
221
|
+
- [x] Environment registry (`register` / `make`) for rebuild-from-a-file replay
|
|
222
|
+
- [x] Sandboxed grading — subprocess (`SubprocessSandbox`) or container (`DockerSandbox`), fail-closed
|
|
223
|
+
- [x] Rubrics — partial-credit rewards from weighted checks
|
|
224
|
+
- [x] Environments: `GuessEnv`, `SQLTaskEnv`, `CodeTaskEnv`, `CommandEnv`, `TerminalEnv`, `HttpTaskEnv`
|
|
225
|
+
- [x] Real git-repo-with-pytest (by composition) — the agent turns real tests green
|
|
226
|
+
- [x] Training export — `{prompt, completion, reward}` / JSONL
|
|
227
|
+
- [x] TRL adapter — a Crucible environment *as* a GRPO reward function
|
|
228
|
+
- [x] verifiers adapter — same bridge for Prime Intellect's stack
|
|
229
|
+
- [x] CI + ≥90% coverage gate (Python 3.11–3.13)
|
|
230
|
+
- [x] Public (MIT); contributions via PR with green CI + a code-owner +1 required
|
|
231
|
+
- [x] Gradio demo app (`space/app.py`) — runs locally (`python space/app.py`)
|
|
232
|
+
- [x] **A real GRPO training run** — a 0.5B model learned a SQL task **5% → 100%**
|
|
233
|
+
with a Crucible environment *as* the reward, no labels; **generalizes** across
|
|
234
|
+
four distinct SQL skills **and three different environment types** (database,
|
|
235
|
+
shell, code) ([`examples/results/`](examples/results/README.md))
|
|
236
|
+
- [x] Packaging — `pip install crucible-rl` (zero-dep core) / `[train]` extra for the
|
|
237
|
+
RL stack; PyPI-publish-ready (metadata, wheel + sdist pass `twine check`)
|
|
238
|
+
|
|
239
|
+
**Next**
|
|
240
|
+
|
|
241
|
+
- [ ] Push the release to PyPI (packaging is ready; `twine upload` pending)
|
|
242
|
+
- [ ] Trajectory commons — shareable, auditable trajectory datasets on the Hub
|
|
243
|
+
- [ ] Host the demo Space *(app is built; hosting deferred — Hugging Face now
|
|
244
|
+
charges for Gradio Spaces, and a free static/`gradio-lite` port is the fallback)*
|
|
245
|
+
- [ ] Learned reward for non-verifiable tasks *(parked — research)*
|
|
246
|
+
|
|
247
|
+
## What it is *not*
|
|
248
|
+
|
|
249
|
+
Crucible is **training/eval infrastructure** (the Gymnasium / Prime-Intellect
|
|
250
|
+
lineage). Its "verification" is programmatic task-success checking for reward. It is
|
|
251
|
+
deliberately **not** a runtime agent-accountability or governance system — a
|
|
252
|
+
different field. See [`docs/VISION.md`](docs/VISION.md) §5.
|
|
253
|
+
|
|
254
|
+
## License & contributing
|
|
255
|
+
|
|
256
|
+
**MIT** ([`LICENSE`](LICENSE)) — fork it and build. The repo is public; contributions
|
|
257
|
+
are welcome via pull request, and every merge needs green CI (Python 3.11–3.13) plus a
|
|
258
|
+
code-owner +1 (see [`CONTRIBUTING.md`](CONTRIBUTING.md)).
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Crucible
|
|
2
|
+
|
|
3
|
+
> **Crucible** — both the vessel that contains and the trial that transforms, which is
|
|
4
|
+
> exactly what an environment does to an agent.
|
|
5
|
+
|
|
6
|
+
**Crucible turns any real software into a trainable, gradable world for AI agents.**
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
Wrap a CLI, a database, a codebase, or an API in a few lines and it becomes an
|
|
11
|
+
*environment*: an agent can be run through it, scored on real outcomes, and — the
|
|
12
|
+
part nobody else has — its whole episode **replayed deterministically**, so every run
|
|
13
|
+
is reproducible and every reward is auditable.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from crucible import rollout, replay
|
|
17
|
+
|
|
18
|
+
traj = rollout(my_env, my_agent, seed=0) # run the agent, record the episode
|
|
19
|
+
report = replay(fresh_env, traj) # re-run and verify it byte-for-byte
|
|
20
|
+
assert report.ok
|
|
21
|
+
traj.save("episode.trajectory.json") # the artifact leaves memory
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Why this exists
|
|
25
|
+
|
|
26
|
+
The frontier of AI moved off pre-training. Models now improve by **doing** —
|
|
27
|
+
reinforcement learning in environments — and the field agrees on the bottleneck:
|
|
28
|
+
*"RL environments are the key bottleneck to the next wave of AI progress, but big
|
|
29
|
+
labs are locking them down."* Environments are the **training data of 2026**, and
|
|
30
|
+
there is no open, easy way to *make* them. The open ecosystem has a hub (Prime
|
|
31
|
+
Intellect) and a training stack (TRL, verifiers, prime-rl) — it does not have a great
|
|
32
|
+
open **authoring layer**. That's the seam Crucible fills. The full argument is in
|
|
33
|
+
[`docs/VISION.md`](docs/VISION.md).
|
|
34
|
+
|
|
35
|
+
## It actually trains a model
|
|
36
|
+
|
|
37
|
+
Not a toy: a `SQLTaskEnv` used *directly* as a GRPO reward — no labels, no hand-written
|
|
38
|
+
reward code — took `Qwen2.5-0.5B-Instruct` from **5% → 100%** on a real SQL task in 80
|
|
39
|
+
steps on a single laptop GPU. The model discovered the query itself, guided only by the
|
|
40
|
+
environment.
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
And it's **not one lucky task** — a fresh model trained on four *distinct* SQL skills
|
|
45
|
+
improved on every one (subquery, `SUM`, `HAVING`, `AVG`). The method trains, not the
|
|
46
|
+
task.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
And **not just SQL** — the identical loop trains *different kinds of agents*: a **shell**
|
|
51
|
+
agent (`CommandEnv`, 70→100%) and a **coding** agent graded by *really running its code*
|
|
52
|
+
(`CodeTaskEnv`, 55→85%), alongside a database agent. Only the environment changes. Full
|
|
53
|
+
runs + how to reproduce: [`examples/results/`](examples/results/README.md).
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install crucible-rl # the zero-dependency core, Python 3.11+
|
|
61
|
+
pip install "crucible-rl[train]" # + the RL stack, to reproduce the GRPO run
|
|
62
|
+
pip install -e ".[dev]" # or hack on it from a clone
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quickstart (60 seconds)
|
|
66
|
+
|
|
67
|
+
Run the built-in demo — three real worlds, each forged and replayed:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python -m examples.demo
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
=== CodeTaskEnv - fix the bug so the test goes green (the reward writes itself) ===
|
|
75
|
+
steps: 2 total reward: +0.90 replay: reproduced OK
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Inspect a saved episode from the terminal:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
crucible show episode.trajectory.json # summary + integrity check
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Core concepts
|
|
85
|
+
|
|
86
|
+
Three nouns, two verbs — the whole core is ~180 lines and imports only the standard
|
|
87
|
+
library.
|
|
88
|
+
|
|
89
|
+
| Piece | What it is |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| **`Environment`** | Real software wrapped with `reset(seed)` / `step(action)` |
|
|
92
|
+
| **`Agent`** | Anything with `act(observation) -> action` (scripted, search, an LLM) |
|
|
93
|
+
| **`Trajectory`** | The replayable episode record (seed, observations, actions, rewards) |
|
|
94
|
+
| **`rollout`** | Drives an agent through an environment and records a Trajectory |
|
|
95
|
+
| **`replay`** | Re-runs a Trajectory against a fresh environment and verifies it |
|
|
96
|
+
|
|
97
|
+
How each of these works internally — the rollout loop, the replay verifier, the
|
|
98
|
+
determinism contract, digests, the on-disk format — is documented to junior-dev
|
|
99
|
+
detail in **[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)**.
|
|
100
|
+
|
|
101
|
+
## Write your own environment
|
|
102
|
+
|
|
103
|
+
Wrap software you already have; implement two methods and (optionally) a digest:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from crucible.env import Environment, StepResult
|
|
107
|
+
|
|
108
|
+
class ReverseStringEnv(Environment):
|
|
109
|
+
def __init__(self, target: str):
|
|
110
|
+
self.target = target
|
|
111
|
+
def reset(self, seed: int):
|
|
112
|
+
return {"task": f"reverse: {self.target!r}"}
|
|
113
|
+
def step(self, action):
|
|
114
|
+
correct = str(action) == self.target[::-1]
|
|
115
|
+
return StepResult(
|
|
116
|
+
observation={"you_said": str(action)},
|
|
117
|
+
reward=1.0 if correct else -0.1,
|
|
118
|
+
done=correct,
|
|
119
|
+
info={"correct": correct},
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The rules that make an environment *replayable* (determinism, JSON-serializable
|
|
124
|
+
observations, verifiable reward, digests) and a full worked example are in
|
|
125
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) §7.
|
|
126
|
+
|
|
127
|
+
## The example environments (`crucible/envs/`)
|
|
128
|
+
|
|
129
|
+
| Env | Shows |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `GuessEnv` | A fully deterministic game — the clean proof that replay reproduces an episode exactly |
|
|
132
|
+
| `SQLTaskEnv` | Wrapping **real SQLite** — reward is programmatic and verifiable (run the query, compare the rows) |
|
|
133
|
+
| `CodeTaskEnv` | The SWE-agent shape — **the test suite is the reward function** (edit files, grader runs, green is the reward) |
|
|
134
|
+
| `CommandEnv` | Wrap any **command-line tool** — the agent emits a command, reward is exit-0 + stdout match (sandboxed, registerable) |
|
|
135
|
+
| `TerminalEnv` | A **stateful shell session** — commands accumulate state across steps (mkdir here, write there); reward is a goal over the workdir |
|
|
136
|
+
| `HttpTaskEnv` | Wrap a **recorded HTTP service** (VCR/cassette) — the agent finds the right request; deterministic and registerable |
|
|
137
|
+
|
|
138
|
+
## The CLI
|
|
139
|
+
|
|
140
|
+
- `crucible show <file>` — summarize a saved episode (env, seed, steps, reward,
|
|
141
|
+
fingerprint) and integrity-check it.
|
|
142
|
+
- `crucible replay <file>` — rebuild the environment from the registry and **re-run**
|
|
143
|
+
the episode, confirming it reproduces (or printing the mismatches). Works for
|
|
144
|
+
registered environments; see [ARCHITECTURE §6c](docs/ARCHITECTURE.md).
|
|
145
|
+
|
|
146
|
+
## Project layout
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
crucible/ the zero-dependency core + example environments
|
|
150
|
+
env.py the Environment contract (reset/step, determinism, digest)
|
|
151
|
+
trajectory.py the replayable record (JSON, versioned save/load, fingerprint)
|
|
152
|
+
rollout.py rollout() records; replay() re-runs and verifies
|
|
153
|
+
registry.py register/make envs by name (powers `crucible replay`)
|
|
154
|
+
reward.py Rubric — partial-credit rewards from weighted checks
|
|
155
|
+
sandbox.py run a grader/command in a subprocess (safe for untrusted code)
|
|
156
|
+
export.py flatten trajectories to {prompt, completion, reward} / JSONL
|
|
157
|
+
cli.py the `crucible` command
|
|
158
|
+
envs/ Guess, SQLTask, CodeTask, Command, Terminal, HttpTask
|
|
159
|
+
examples/ demo, agents, and the GRPO training runs + results (not packaged)
|
|
160
|
+
tests/ the suite (100% coverage, enforced in CI)
|
|
161
|
+
docs/ VISION (why), ARCHITECTURE (how), BACKLOG (what's next)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pip install -e ".[dev]"
|
|
168
|
+
pytest # runs the suite; pyproject enforces --cov-fail-under=90
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
CI (`.github/workflows/ci.yml`) runs the same gate on Python 3.11–3.13. Every change
|
|
172
|
+
ships with tests and moves the docs in the same commit (see
|
|
173
|
+
[`CONVENTIONS.md`](CONVENTIONS.md)).
|
|
174
|
+
|
|
175
|
+
## Status & roadmap
|
|
176
|
+
|
|
177
|
+
**V1 (the MVP) is complete**, and the repo is **public under MIT** with tests, CI,
|
|
178
|
+
and a code-owner +1 required to merge. Author → run → grade → replay → persist, as a
|
|
179
|
+
real tool, on one code path, 100% coverage. Where it goes from here — the three-phase
|
|
180
|
+
direction — is in **[`ROADMAP.md`](ROADMAP.md)**; the per-item "how to build it" detail
|
|
181
|
+
is in **[`docs/BACKLOG.md`](docs/BACKLOG.md)**. Progress at a glance:
|
|
182
|
+
|
|
183
|
+
**Built**
|
|
184
|
+
|
|
185
|
+
- [x] Core — `Environment` contract, `Trajectory`, `rollout`, `replay`
|
|
186
|
+
- [x] Deterministic replay that verifies the whole episode (observations, rewards, digests)
|
|
187
|
+
- [x] Trajectory persistence (versioned format) + `crucible show` / `crucible replay` CLI
|
|
188
|
+
- [x] Environment registry (`register` / `make`) for rebuild-from-a-file replay
|
|
189
|
+
- [x] Sandboxed grading — subprocess (`SubprocessSandbox`) or container (`DockerSandbox`), fail-closed
|
|
190
|
+
- [x] Rubrics — partial-credit rewards from weighted checks
|
|
191
|
+
- [x] Environments: `GuessEnv`, `SQLTaskEnv`, `CodeTaskEnv`, `CommandEnv`, `TerminalEnv`, `HttpTaskEnv`
|
|
192
|
+
- [x] Real git-repo-with-pytest (by composition) — the agent turns real tests green
|
|
193
|
+
- [x] Training export — `{prompt, completion, reward}` / JSONL
|
|
194
|
+
- [x] TRL adapter — a Crucible environment *as* a GRPO reward function
|
|
195
|
+
- [x] verifiers adapter — same bridge for Prime Intellect's stack
|
|
196
|
+
- [x] CI + ≥90% coverage gate (Python 3.11–3.13)
|
|
197
|
+
- [x] Public (MIT); contributions via PR with green CI + a code-owner +1 required
|
|
198
|
+
- [x] Gradio demo app (`space/app.py`) — runs locally (`python space/app.py`)
|
|
199
|
+
- [x] **A real GRPO training run** — a 0.5B model learned a SQL task **5% → 100%**
|
|
200
|
+
with a Crucible environment *as* the reward, no labels; **generalizes** across
|
|
201
|
+
four distinct SQL skills **and three different environment types** (database,
|
|
202
|
+
shell, code) ([`examples/results/`](examples/results/README.md))
|
|
203
|
+
- [x] Packaging — `pip install crucible-rl` (zero-dep core) / `[train]` extra for the
|
|
204
|
+
RL stack; PyPI-publish-ready (metadata, wheel + sdist pass `twine check`)
|
|
205
|
+
|
|
206
|
+
**Next**
|
|
207
|
+
|
|
208
|
+
- [ ] Push the release to PyPI (packaging is ready; `twine upload` pending)
|
|
209
|
+
- [ ] Trajectory commons — shareable, auditable trajectory datasets on the Hub
|
|
210
|
+
- [ ] Host the demo Space *(app is built; hosting deferred — Hugging Face now
|
|
211
|
+
charges for Gradio Spaces, and a free static/`gradio-lite` port is the fallback)*
|
|
212
|
+
- [ ] Learned reward for non-verifiable tasks *(parked — research)*
|
|
213
|
+
|
|
214
|
+
## What it is *not*
|
|
215
|
+
|
|
216
|
+
Crucible is **training/eval infrastructure** (the Gymnasium / Prime-Intellect
|
|
217
|
+
lineage). Its "verification" is programmatic task-success checking for reward. It is
|
|
218
|
+
deliberately **not** a runtime agent-accountability or governance system — a
|
|
219
|
+
different field. See [`docs/VISION.md`](docs/VISION.md) §5.
|
|
220
|
+
|
|
221
|
+
## License & contributing
|
|
222
|
+
|
|
223
|
+
**MIT** ([`LICENSE`](LICENSE)) — fork it and build. The repo is public; contributions
|
|
224
|
+
are welcome via pull request, and every merge needs green CI (Python 3.11–3.13) plus a
|
|
225
|
+
code-owner +1 (see [`CONTRIBUTING.md`](CONTRIBUTING.md)).
|