A verifier-guided reasoning engine: search (best-of-N, beam, MCTS) over reasoning traces to turn test-time compute into measured accuracy.
Project description
Crucible
A verifier-guided reasoning engine: generate many reasoning traces from a small open model, score them with a verifier (programmatic checker or a process-reward model), and search — best-of-N → beam → MCTS over reasoning steps — to turn test-time compute into measurable accuracy on math and code.
Who it's for, and why this and not the obvious thing. Crucible is for engineers and researchers who need to know — not assume — what test-time search actually buys on a model they control. The obvious alternative is to call a reasoning model and trust its benchmark table, or to hand-roll a best-of-N script; the first tells you nothing about your policy, and the second almost always reports a lift it didn't pay for. Crucible is the instrument instead of the anecdote: it plots accuracy against total tokens with the verifier's own compute counted, reports the outcome verifier on the chosen trace (never a PRM score), puts Wilson CIs and a named bigger-model baseline next to every claim — and publishes the results when search loses. It does lose here, twice; that's the point. Design rationale: DESIGN.md.
The headline — real model, real PRM, real data. 3-seed MATH-500, frozen
qwen2.5:1.5b-instruct (Ollama) + a real Skywork 1.5B PRM (GPU): search lifts pass@1
38.3% → 70% (oracle) at N=8, and on identical samples the learned PRM beats
self-consistency majority at every N (N=4: 53.3% vs 45.0%). The caveats, all measured, none
buried:
- the PRM's ~2× compute makes it ≈ a wash with majority at matched tokens;
- a 7B baseline (67.5% pass@1 @ 524 tok) is more compute-efficient than 1.5B + search — small-beats-big fails on this stack;
- real beam (0/8) and MCTS (1/8) on the hardest problems are the most expensive methods and don't win.
Full write-up, every number and caveat: docs/RESULTS.md §0.
Reproduce the headline in one command — no GPU, no network, no model. It replays the recorded real runs from committed cassettes:
make demo # no make on Windows? use the line below:
python -m crucible bench curve tests/fixtures/math500-bestofn-seed*.json
Status: M0–M7 built; the real curves are captured and replay in CI. Behind one policy/verifier/search interface: best-of-N (M2), PRM selection + the selection gap (M3), PRM-guided beam/DVTS (M4), a sandboxed code track (M5), MCTS (M6), the compute-optimal report (M7), plus hardening (H1 ✓, H3 ✓, H4 ✓; H2 measured — an honest negative). Open: a favorable real result for beam/MCTS (M4/M6) and small-beats-big (H2) both need a stronger PRM / a reasoning policy; M5's real HumanEval run is still unrun. See ROADMAP.md · PROGRESS.md.
Run it
Prerequisites: Python ≥ 3.11 (check: python --version). No GPU or network needed
for the M0 demo; real model backends (Ollama, etc.) come in from M1.
Naming: the project is Crucible, distributed on PyPI as
crucible-ttc(ttc = test-time compute), imported ascrucible, and invoked ascrucibleon the command line (pip install crucible-ttconce published; the commands below install from source).
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
# Offline demo — generate, verify, and report pass@1 on the bundled sample set:
python -m crucible run --method pass1 --dataset sample --policy mock
You should see a per-problem table and a 66.7% (4/6) pass@1 with a Wilson
confidence interval, and a run record written under runs/.
Real model runs (M1): install the dataset extra, start Ollama and pull a small instruct model, then run real pass@1 on GSM8K:
pip install -e ".[datasets]"
ollama pull qwen2.5:1.5b-instruct # the captured runs' policy model
python -m crucible run --method pass1 --dataset gsm8k --policy ollama `
--model qwen2.5:1.5b-instruct --limit 20
The real lift curve (H1/H3): capture it once on a GPU, regenerate it offline forever.
bench record samples N×/problem and scores each with the outcome verifier + PRM into a
cassette; bench curve computes accuracy-vs-compute for every N/selector from the cassette
(no GPU). Chunk long captures with --offset/--limit (a crash saves progress and prints
the resume offset), merge the chunks, and pool seeds by passing several cassettes:
# One line per seed (needs the prm+datasets extras, Ollama, and a GPU):
crucible bench record --dataset math500 --model qwen2.5:1.5b-instruct `
--prm Skywork/Skywork-o1-Open-PRM-Qwen-2.5-1.5B --max-n 8 --limit 40 --seed 0 --out runs/m500-s0.json
crucible bench curve runs/m500-s0.json runs/m500-s1.json runs/m500-s2.json # pooled curve, offline
# Reproduce the committed headline with no GPU:
crucible bench curve tests/fixtures/math500-bestofn-seed*.json
The offline lift-curve demo (M2): the synthetic-policy curve, no model needed:
python -m crucible sweep configs/sample-sweep.yaml # writes runs/sweep-*/curve.png
The PRM selection gap (M3): compare majority / PRM / oracle selection on the same best-of-N samples (offline, mock PRM):
python -m crucible compare # writes runs/compare-*/comparison.png (oracle >= prm >= majority)
The full search ladder at matched compute (M4/M6): pass1 vs best-of-N vs beam vs MCTS on a synthetic stepwise task, offline:
python -m crucible sweep configs/beam-sweep.yaml # one curve, all four methods
The headline report (M7): the multi-seed ladder with Wilson CIs + the compute-optimal frontier; interpreted in docs/RESULTS.md:
python -m crucible sweep configs/results.yaml # 3 seeds; curve.png has the dashed frontier
The code track (M5): execute model-generated code against unit tests in a
locked-down sandbox. Execution is off by default — pass --allow-code-exec:
python -m crucible run --dataset code-sample --policy mock --allow-code-exec # 2/3
Commands
| Command | What it does |
|---|---|
crucible run [...] |
Run one experiment (method × dataset × backend) and report it |
crucible report <run_dir> |
Print the metrics from a past run |
crucible sweep <config.yaml> |
Grid → the accuracy-vs-compute curve (M2) |
crucible bench record/merge/curve |
Capture a real lift curve once (sample N×/problem, score offline), pool seeds, overlay beam/MCTS runs — the headline artifact (H1/H3) |
crucible compare |
Majority/PRM/oracle on the same samples → the selection gap (M3) |
crucible run --dataset code-sample --allow-code-exec |
Code track: sandboxed execution (M5) |
crucible run … --record <path> |
Record a live run to a cassette that replays offline in CI (H3) |
crucible version |
Print the version |
make demo · make check |
The offline real-results demo · lint + typecheck + test |
ruff check . · mypy src · pytest |
Lint · typecheck · tests |
What Crucible can't do
An honest instrument publishes its limits, not just its wins:
- It won't make a weak policy strong. On MATH-500's hardest problems the 1.5B policy's pass@1 is 0%; search lifts that to 12–17%, not to competence. A bigger model (7B pass@1 67.5%) beats 1.5B + search at a fraction of the compute — small-beats-big does not hold here (it needs a stronger PRM than the 1.5B Skywork).
- Stepwise search (beam/MCTS) doesn't help a non-reasoning instruct policy. Asked to
continue a partial trace,
qwen2.5:1.5b-instructrestarts instead — so beam scores 0/8 at ~37k tokens/problem. Beam/DVTS is a reasoning-policy phenomenon; this stack can't show its win. - No training. Policies and PRMs are frozen — no fine-tuning, RL, or self-improvement (an explicit v1 non-goal).
- The code sandbox is a guardrail, not a jail (subprocess + timeout + no network + scratch dir; opt-in). Use Docker/WSL2 for genuinely untrusted code. See ADR-0003.
- Single node, one GPU. No multi-GPU or distributed orchestration.
- Statistics are modest. Curves pool 40 problems × 3 seeds; the seeds share problems, so CIs are mildly optimistic and close margins are suggestive, not decisive. The compute axis counts tokens, not FLOPs (which flatters small models). Full list: RESULTS §6.
crucible and python -m crucible are equivalent. Optional extras install per
milestone: ".[datasets]" (M1), ".[prm]" (M3), ".[vllm]".
How to give feedback
When reporting an issue or a run:
- Run the Test steps for the current milestone in ROADMAP.md.
- Describe what happened in plain language; paste any errors verbatim (the single most useful thing); include the printed metrics table for a run.
Project docs
| Doc | What's in it |
|---|---|
| DESIGN.md | The full design and rationale — the single source of truth. |
| docs/RESULTS.md | The results report — the lift curve, interpreted honestly. |
| ROADMAP.md | The milestone checklist (the plan + what's done). |
| PROGRESS.md | Build log: what shipped each milestone and why. |
docs/ |
Long-form docs and architecture decisions (ADRs). |
Tech stack
Python 3.11+ · Typer CLI over YAML config · ports-and-adapters core ·
math-verify + SymPy (math equivalence) · httpx (Ollama backend) ·
pandas + matplotlib (reporting) · pytest · ruff · mypy(strict). Inference backends are
swappable adapters behind one port — mock/synthetic/stepwise (offline, drive the
tests) and ollama (the real backend used for every captured result); a vLLM/hosted
adapter slots in the same way. PRM scoring (transformers + torch) and the HuggingFace
dataset loaders live behind the prm and datasets extras, so the base install stays
light and the whole test suite runs with no GPU.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crucible_ttc-0.1.0.tar.gz.
File metadata
- Download URL: crucible_ttc-0.1.0.tar.gz
- Upload date:
- Size: 664.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17c69b082742bea6ce92ea633ab9f6c544e877897587b312140ecb8697d969fa
|
|
| MD5 |
b2f51b834d0a7956ef200d6c11253846
|
|
| BLAKE2b-256 |
836a195ffd11474ec845bb50cea5e1da368423217997e3137d97db181cb7a70e
|
Provenance
The following attestation bundles were made for crucible_ttc-0.1.0.tar.gz:
Publisher:
publish.yml on satchmakua/crucible-ttc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crucible_ttc-0.1.0.tar.gz -
Subject digest:
17c69b082742bea6ce92ea633ab9f6c544e877897587b312140ecb8697d969fa - Sigstore transparency entry: 2232789692
- Sigstore integration time:
-
Permalink:
satchmakua/crucible-ttc@fb470194db4abf0fccee213a57e9cc05d70ffe03 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/satchmakua
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fb470194db4abf0fccee213a57e9cc05d70ffe03 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file crucible_ttc-0.1.0-py3-none-any.whl.
File metadata
- Download URL: crucible_ttc-0.1.0-py3-none-any.whl
- Upload date:
- Size: 72.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9ceac0f5bea7c3af19d22f0835e3d9e65daabed15514cbc03057dc16a4eb028
|
|
| MD5 |
1d16f2cd6a86328af48e30ae63801754
|
|
| BLAKE2b-256 |
b912194b3940112519fd458126f219e1317fa46d466d4e23656fb25d9577121a
|
Provenance
The following attestation bundles were made for crucible_ttc-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on satchmakua/crucible-ttc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crucible_ttc-0.1.0-py3-none-any.whl -
Subject digest:
a9ceac0f5bea7c3af19d22f0835e3d9e65daabed15514cbc03057dc16a4eb028 - Sigstore transparency entry: 2232790234
- Sigstore integration time:
-
Permalink:
satchmakua/crucible-ttc@fb470194db4abf0fccee213a57e9cc05d70ffe03 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/satchmakua
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fb470194db4abf0fccee213a57e9cc05d70ffe03 -
Trigger Event:
workflow_dispatch
-
Statement type: