Weight-space programming, end to end. An LLM reads a neural network's weights and edits them directly: no gradient descent, no training pipeline. wsplab runs the whole job, from the baseline to a verdict, and packages the edit as a small patch anyone can apply to the public base model.
import wsplab
run = wsplab.run(
"Qwen/Qwen3.5-0.8B",
note="This model really sucks at math",
eval="math",
editor="anthropic:claude-opus-5-5",
thinking=True,
budget=25,
)
print(run.verdict, run.patch)
print(run.generate("What is 17 * 23?"))
Or the same job from the command line:
wsplab run --model Qwen/Qwen3.5-0.8B --note "This model really sucks at math" --eval math \
--editor anthropic:claude-opus-5-5 --thinking --budget 25
Based on Sparks of Weight-Space Programming by Takehi, Teoh, Zhang and Khattab. wsplab is independent and is not affiliated with or endorsed by the authors.
What it does
- Runs everything. It scores the network, then gives the editor a sandboxed kernel and a budget of forward passes. It builds the edit, scores it again on data the editor never saw, and reaches a verdict.
- Works on any network. Language models and any PyTorch network: a game policy, a CNN and a diffusion model take the same path and differ only in how they are scored.
- Uses the paper's method. The same base prompt, turn protocol and editing surface. The editor writes its own scripts to inspect the weights, so nothing has to fit in context and nothing is pre-summarized. Replaying the authors' sessions reproduces their prompts byte for byte.
- Tells you when it didn't work. A hidden evaluation, paired statistics and a same-size random-edit control
decide the verdict, not the editor.
no_fix_foundis a normal outcome. - Makes edits shareable. A patch is a few small files that rebuild the edited model bit for bit from the public base. Patches can be verified, stacked and shared on the Hugging Face Hub.
- Lets you go as low as you want. From one call down to raw tensors, including replacing the whole prompt.
- One editor by default; a council of peers is optional. Several LLMs can edit side by side and see each other's work. The findings say when that helps (rarely).
Install
pip install wsplab # patch tools only: needs just numpy
pip install 'wsplab[torch,kernel]' # run any PyTorch network
pip install 'wsplab[lm,vllm,eval,hub]' # language models
wsplab setup # builds the sandbox environment, once
wsplab doctor # says what this machine can run
- GPU versions:
constraints-gpu.txtlists the versions tested together for language models; add-c constraints-gpu.txt. No CUDA toolkit is needed. - Sandbox: editing sessions run in bubblewrap on Linux.
- Python: 3.12 or later.
Editor API keys
The editor is an LLM you call with your own account. wsplab reads the provider's usual environment variable:
--editor / editor= |
Key |
|---|---|
anthropic:<model> |
ANTHROPIC_API_KEY |
openai:<model> |
OPENAI_API_KEY |
openai-chat:<model> |
OPENAI_API_KEY, sent to the server at OPENAI_BASE_URL |
codex:<model> |
None: the Codex CLI's own login (codex login) |
export ANTHROPIC_API_KEY=sk-ant-...
wsplab run ... --editor anthropic:claude-opus-5-5
Any OpenAI-compatible provider works through openai-chat:. For Gemini, for example:
export OPENAI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/ OPENAI_API_KEY=<your Gemini key>
wsplab run ... --editor openai-chat:gemini-4-argon
In Python, pass keys directly instead, which also lets one council mix providers that would otherwise share
OPENAI_API_KEY:
from wsplab.editors import AnthropicEditor, ChatEditor, OpenAIEditor
editors = [AnthropicEditor("claude-opus-5-5", api_key=...),
OpenAIEditor("gpt-6.1-terra", api_key=...),
ChatEditor("gemini-4-argon", api_key=..., base_url="https://generativelanguage.googleapis.com/v1beta/openai/")]
Keys stay on the host. The sandbox the editor's code runs in starts with an empty environment and no network, so that
code can't read or send them. This holds for the default sandbox, not for --sandbox none.
A network of your own
from wsplab.eval.suites import ArrayScorer
run = wsplab.run(net, build=build_net, description="a small image classifier",
note="It confuses cats and dogs", evaluate=ArrayScorer(images, labels),
editor="anthropic:claude-opus-5-5", budget=10, max_changed=5_000)
print(run.verdict, run.infer(new_images))
max_changed is an optional edit budget: save_edit refuses edits that would change more entries than that.
Command line
Every step has a command, and wsplab <command> --help lists all its options.
| Command | What it does |
|---|---|
wsplab run |
The whole job: baseline, editing session, final evaluation, verdict and patch |
wsplab eval |
Score a network, with or without a patch |
wsplab infer |
Run a network, with or without a patch |
wsplab patch ... |
Create, apply, verify, inspect, stack and share patches |
wsplab session ... |
Be the editor yourself, step by step (for coding agents) |
wsplab setup, wsplab doctor |
Build the sandbox once; check what this machine can run |
Edit a language model
--eval math is the paper's task: the editor practises on the paper's released problems, and the verdict comes from
MATH-500, which the editor never sees.
wsplab run --model Qwen/Qwen3.5-0.8B --note "This model really sucks at math" \
--eval math --samples 4 --limit 200 --thinking \
--editor anthropic:claude-opus-5-5 --budget 25 --out runs/qwen-math
It ends by printing the verdict and where everything went:
verdict: confirmed # or not_significant, regressed, no_fix_found, unmeasured
... # the reasons for the verdict
patch: runs/qwen-math/result/patch
report: runs/qwen-math/report.md
For a task of your own, give a practice set and a held-out set as .jsonl files, one
{"id": ..., "problem": ..., "answer": ...} per line. --grader is exact, math, choice or regex:<pattern>:
wsplab run --model Qwen/Qwen3.5-0.8B --practice practice.jsonl --eval heldout.jsonl --grader exact \
--note "It answers in English when asked in French" --editor openai:gpt-6.1-terra --budget 15
Edit any PyTorch network
Give the weights, a way to build the network, and .npz files holding arrays named inputs and targets:
wsplab run --model net.safetensors --build model.py:build --description "a small image classifier" \
--note "It confuses cats and dogs" --practice practice.npz --eval heldout.npz \
--editor anthropic:claude-opus-5-5 --budget 10 --max-changed 5000 --out runs/cats
--build:path/model.py:function, where the function returns thenn.Module. A plain MLP can be written inline instead, such asmlp:784,128,10:relu.--description: completes the sentence "You are given the weights of ...".- Limits:
--max-changedcaps how many weight entries the edit may change, and--frozen <tensor>(repeatable) keeps a tensor unchanged. - Scoring:
--metric accuracy(the default) orneg_msefor regression. - No held-out set:
--no-evalaccepts anunmeasuredverdict.
Check the result yourself
eval and infer run the base model, or the base model with a patch applied:
# any network
wsplab eval --model net.safetensors --build model.py:build --data heldout.npz
wsplab eval --model net.safetensors --build model.py:build --data heldout.npz --patch runs/cats/result/patch
wsplab infer --model net.safetensors --build model.py:build --patch runs/cats/result/patch \
--input batch.npy --out predictions.npy
# a language model
wsplab eval --model Qwen/Qwen3.5-0.8B --suite math --limit 200 --patch runs/qwen-math/result/patch
wsplab infer --model Qwen/Qwen3.5-0.8B --patch runs/qwen-math/result/patch --prompt "What is 17 * 23?"
Choose the editor
--editor takes anthropic:<model>, openai:<model>, codex:<model>, or openai-chat:<model> for any
OpenAI-compatible server (see An open-source editor). Editor API keys
says where each one finds its key.
Repeat --editor for a council of peers. A council needs a spending limit, --max-tokens or --max-usd. A dollar
limit needs a price for each editor, in dollars per million input and output tokens. The prices below are examples;
use your provider's:
wsplab run --model net.safetensors --build model.py:build --description "a small image classifier" \
--practice practice.npz --eval heldout.npz --budget 8 \
--editor anthropic:claude-opus-5-5 --editor openai:gpt-6.1-terra \
--max-usd 10 --price anthropic:claude-opus-5-5=5,20 --price openai:gpt-6.1-terra=1,5
From the command line, councils work on PyTorch networks. Use the Python API for a council on a language model.
Be the editor
A coding agent, or you, can do the editor's job one step at a time. Each step is checked against the same rules and budget as an LLM editor:
wsplab session start --folder s1 --model net.safetensors --build mlp:2,4,2:relu \
--description "a two-class classifier" --note "It answers backwards" \
--practice practice.npz --eval heldout.npz --budget 10
wsplab session exec s1 --file inspect.py --why "first, look at the weights"
wsplab session forward s1 '{"model": "both"}' --why "measure the edit"
wsplab session finish s1 "What I changed, the evidence, and why it should help."
finish prints the verdict. wsplab session brief s1 prints the latest message, and /work in the kernel is
s1/run/work on the host.
An open-source editor
Any model behind an OpenAI-compatible chat server can be the editor. The protocol is plain text, so no tool calling is needed:
vllm serve Qwen/Qwen3-32B --max-model-len 65536 # sessions need long context
export OPENAI_BASE_URL=http://localhost:8000/v1 OPENAI_API_KEY=local
wsplab run --model net.safetensors ... --editor openai-chat:Qwen/Qwen3-32B
run = wsplab.run(net, ..., editor="openai-chat:Qwen/Qwen3-32B")
# or, to mix servers in one council: ChatEditor("Qwen/Qwen3-32B", base_url="http://host:8000/v1", api_key="local")
For limits on local models, which have no prices, use --max-tokens or Spending(max_tokens=...). Tested end to
end with a vLLM-served Qwen3.5-0.8B: the session ran, but a model that small couldn't do the job. Expect to need a
strong open model.
Progress and logs
A run says what it is doing as it goes: which step it is on, how far generation has got and how long is left, and one
line per editor turn. The same lines go to run.log in the run's folder, so a run in the background can be followed
with tail -f:
09:12:03 MATH-500: 500 held-out items x 4 answers, up to 32,768 new tokens each with thinking; 14,744 practice items
09:12:03 each evaluation generates up to 65.5M tokens; this run has up to 3 (baseline, edited model, random-edit control)
09:41:17 baseline evaluation: 160/2,000 answers (8%), 1,310 tokens/s, about 5h 36m left
...
15:02:44 turn 7: forward pass 2/25: model both, items 64, original 0.172, edited 0.25, difference +0.078 ± 0.03, 9m 12s | ...
- Quieter:
quiet=Truein Python, orwsplab -q run ..., keeps onlyrun.log.wsplab -vprints more detail. - Your own logging: messages go to the
wsplablogger. If you have set up logging, they go to your handlers instead of being printed. - Nothing from the evaluation goes into a message: only counts, scores and timings.
- Interrupted? The last line says how to resume.
A council of peers (optional)
from wsplab.editors import Spending
found = wsplab.search(net, build=build_net, description="a small image classifier", practice=practice,
evaluate=heldout, editors=["anthropic:claude-opus-5-5", "openai:gpt-6.1-terra"],
shared=True, spending=Spending(max_usd=10, prices={...}))
Each peer edits its own copy and sees the others' work after every step. The best candidate on a held-out selection
set wins, and the original is kept if none beats it. On the command line, repeat --editor. See
docs/council.md.
Patches
A patch is the edit alone: a few small files that rebuild the edited model bit for bit from the public base.
wsplab patch pull user/some-patch --out patch/ # from the Hugging Face Hub
wsplab patch verify patch/ --base Qwen3.5-0.8B/ # does it fit this base?
wsplab patch apply patch/ --base Qwen3.5-0.8B/ --out edited/ # the edited model
wsplab patch push patch/ --repo you/your-patch # share one
For a real one, try Ahmedn1/wsplab-patch-minatar-seaquest.
Claude Opus 5.5 changed 32 weights of the paper's Seaquest policy, and mean return rose from 52.1 to 75.7 over 2,000
held-out episodes. The repo includes the base network and the full session transcript.
A patch's hashes prove what it is and that it fits the base model. They don't prove it is safe or that its claims hold.
With a coding agent
skills/wsplab is an agent skill. It teaches an agent to launch runs, or to act as the editor itself through
wsplab session. Copy it into your agent's skills folder.
Findings
We ran 11 experiments with real editors on one laptop. Read the findings, with charts:
- wsplab reproduces the paper's measurements: the released patches rebuild bit for bit and the prompts replay byte for byte.
- Editing works on steerable behaviour: on the paper's Seaquest policy, strong editors raised the score from 52 to 76 with 32 weights changed. It doesn't work on missing capability (Gemma math, multilingual math).
- A two-line scripted recipe matched or beat LLM editors on Spurious ImageNet.
- Councils lift their weakest member but didn't beat the strongest on any natural task. Cheap councils and fixed roles did worse.
Everything needed to reproduce them, including code, plans, result files and commands, is in
experiments/.
How wsplab compares
Several weight-space programming projects appeared in November 2026. As of 8 November, from their public READMEs:
| wsplab | dspy-wsp | weightspace | wsp-kit | WSP-toolkit | |
|---|---|---|---|---|---|
| LLM writes the edits | yes | yes (a DSPy LM) | yes | no (a numerical estimator) | via tool calls |
| Language models | yes (vLLM, HF) | yes (vLLM, HF, MLX) | yes | small LLMs (≤ 3B) | Qwen3, Llama |
| Any PyTorch network | yes | decision models | not stated | no | no |
| Sandboxed kernel | bubblewrap | bubblewrap | Python sandbox | not stated | not stated |
| Budgeted forward-pass tool | yes | yes | not stated | no | no |
| Hidden evaluation + paired stats + random control | yes | holdout + valset, no control | not stated | metric thresholds | separate test set |
| Patches rebuilt bit for bit from the base | yes, plus Hub, stacking | yes | checkpoints | edited folder | replayable patches |
| Paper fidelity checks (byte-for-byte replay) | yes | no | no | no | no |
| Multiple editors | peers (optional) | population search (GEPA) | no | no | no |
| CLI and agent skill | yes, plus agent-as-editor sessions | CLI | no | CLI, skill, MCP | MCP |
dspy-wsp is the closest in scope, and it adds things wsplab lacks: DSPy integration and a population search over candidate edits. Other related projects are agent skills (di37, GriMReapeR-666), a research harness for coding agents (mfaseehuddin/wsp) and a browser version (webWeightSpace). None of their code is used here.
Read more
- Concepts: kinds, modes, access and control levels.
- Patches: the format and how to share one.
- Councils of peers.
- Fidelity to the paper: what is the authors' work, what is reconstructed, and what differs.
- Findings and experiments.
- Changelog.
Citing
See CITATION.cff. Please also cite the paper.
License
MIT. Prompt text derives from the authors' release under CC BY 4.0: see NOTICE.
Metadata
Release files for wsplab 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| wsplab-0.2.0.tar.gz | 108.4 kB | With provenance | Details for wsplab-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| wsplab-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for wsplab-0.2.0-py3-none-any.whl |
Total release size: 240.3 kB
Release files / wsplab-0.2.0.tar.gz
| Download URL | wsplab-0.2.0.tar.gz |
|---|---|
| Size | 108.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
070868db28023261d709e8b4098aefad7deda8afe37a2d1e00dde8236c794ce4
|
|
BLAKE2b-256 checksum How to use checksums |
0d311f528a127f29b3f78afd0133adbb5c8cecc0f28eb7894148a50ec9a422d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logRelease files / wsplab-0.2.0-py3-none-any.whl
| Download URL | wsplab-0.2.0-py3-none-any.whl |
|---|---|
| Size | 131.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
98f894f510c0382e802eef77d5ff6992726eb36899f12dd9f35d63e90e54ee67
|
|
BLAKE2b-256 checksum How to use checksums |
da1b920518952305e44f20c2127ce3ae8ec211d34e6ee4820135f9a639ccc053
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logSecurity for wsplab 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for wsplab-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.