Experiment 3 doesn't involve reading the weights in as part of the prompt. It's a coding exercise. Here are the turns: github.com/RikiyaT/lm_understand-logs/tree/main/e…
At each point the model has to write code to read the weights in with Python and some other Python code to perform analysis, like this: github.com/RikiyaT/lm_understand-logs/blob/main/e…
My complaint is that the post presents a confusing mix of experiments that imply capabilities that are more than the sum of their parts. This experiment 3 has nothing to do with experiment 1 for instance. In experiment 1 the model does read in the raw weights like it's reading an image.
GPT-6 Astra Edited Qwen3.5-0.8B's Weights. The MATH-500 Jump Was a Loop Fix
GPT-6 Astra got the raw weights of Qwen3.5-0.8B and a Python kernel with no GPU. It changed 131,072 weights, 0.016% of the model, using no gradients, no optimizer and no fine-tuning data. MATH-500 went from 7.9% to 48.1%.
The thread passed 2,600 points on Hacker News. The headline leaves out that in the 7.9% baseline, 93% of the model's MATH-500 answers ran out of tokens before reaching an answer. What Astra actually did was stop a 0.8B model from looping, which is a long way from teaching it math. One HN commenter cites 77.6% on the same test for Qwen's own small reasoning model.
I'll go through what the edit changed and why the baseline is the weak spot, then show how to run the edited Qwen3.5-0.8B with transformers, vLLM, llama.cpp or Ollama so you can check it yourself.
What "weight-space programming" means
The write-up is Sparks of Weight-Space Programming by Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab at MIT CSAIL, posted November 2, 2026. A general-purpose LLM reads and writes another network's weights directly, the way you'd read and patch source code.
Qwen is experiment 8 of 8. I found the earlier ones more surprising:
- Astra named the game (Breakout, Pong, Pac-Man, Freeway) each of four 17,253-weight PPO policies was trained on, from the weights alone.
- It fixed a Kinetix car-on-ramp policy that had never succeeded in 256 episodes. One edit changed 3.5% of the weights, and the car succeeded in all 1,024 evaluation episodes.
- Starting from all-zero weights, it wrote a MinAtar Breakout policy that scored 517.4. PPO scored 25.3 after 500M steps.
Only after those did they point it at a real 24-layer language model.
Qwen3.5-0.8B MATH-500, GSM8K and IFEval results
Setup: thinking on, up to 32,768 tokens, temperature 0.6, top-p 0.95, top-k 20, presence penalty 1.5. Astra could practice on 7,469 GSM8K and 7,275 MATH training problems (no test sets) and got a budget of 10, 25 or 50 forward passes. One "forward pass" means the model answers up to 512 problems or reads up to 1,024 texts.
| Model | MATH-500 | GSM8K | IFEval | MATH-500 answers hitting token limit |
|---|---|---|---|---|
| Base | 7.9% | 13.8% | 21.0% | 93.0% |
| Edited, 10 passes | 12.3% | 25.7% | 49.0% | 87.2% |
| Edited, 25 passes | 14.1% | 25.1% | 39.9% | 86.4% |
| Edited, 50 passes | 48.1% | 67.1% | 62.3% | 33.1% |
Read the last column first. With thinking on, the base model almost never finishes: 85 of its first 96 practice answers hit the 32k ceiling. Astra traced the looping to one direction written by the MLPs of layers 15 and 19 and subtracted it from 64 output columns in each layer. Once the model stops looping, it reaches the end of its reasoning and writes down answers it could already get.
The scores track the loops. At 10 and 25 passes the authors say "the loops barely went away," and MATH-500 stayed in the low teens. The whole headline comes from the 50-pass run.
Why the 7.9% baseline is the weak spot
Gemma shows the edit only fixes a bug that's already there. The team ran the same procedure on Gemma 3 270M, which hits its token limit on only 8.5% of answers. MATH-500 went 6.8% → 7.0% → 7.6% → 7.7% → 7.0% across 5 to 50 passes, which is noise. The authors' conclusion: editing can remove an obstacle, but it can't add an ability the model doesn't have.
Qwen also documents the bug itself. The Qwen3.5-0.8B model card says the 0.8B "is more prone to entering thinking loops compared to other Qwen3.5 models" and that it "operates in non-thinking mode by default." So the baseline is the model in its least reliable mode. On HN, pama wrote that "the nonthinking qwen" model scored 55.2% on MATH-500, above the edited 48.1%, and that the original Qwen reasoning model got 77.6%. They wondered whether the 7.9% was "a vllm or setup bug." Their comment says "0.6B", so it's not clear they measured this exact checkpoint. kristopolous said that turning thinking off on the base Qwen gets "52.0% on their evals." Neither is a controlled reproduction, but both point the same way. porridgeraisin added that the prompt Claude Code wrote for Astra already described the looping bug, so by that account Astra didn't discover it.
The other HN objection is that this is just a steering vector. Subtracting one direction from 64 columns in two down_proj matrices is mechanically very close to abliteration, which removes a refusal direction the same way. yurimo, who says part of their research is in weight-space learning, called it "basically a steering vector, a very established technique" and said "the blog writing and subsequent posting overstate the results." theptip said the experiments "muddy the water": the early experiments showed one-shot weight reading, while the Qwen result is "more of a classic steering vector intervention."
I agree with the critics on the headline. The Qwen result is the weakest experiment in the post, and it got the attention. The Kinetix fix and the from-scratch Breakout policy deserve it more. A frontier model reading raw weight matrices and producing a working policy with no training loop is new; turning down a loop direction in a model whose vendor already warns about loops isn't.
Credit where it's due, though: Astra found a 0.016% edit that cut truncation from 93% to 33%, and the authors published the full Astra logs. I'd call that decent interpretability work. I wouldn't call it a math result.
How to run the edited Qwen3.5-0.8B locally
The official release is RikiyaT/Qwen3.5-0.8B-weight-space-programming: Apache-2.0, safetensors, BF16/F32. Only two tensors differ from the base model, model.language_model.layers.15.mlp.down_proj.weight and layers.19.mlp.down_proj.weight. There's also a hosted demo.
The card includes an independent re-run by akhaliq with the post's vLLM settings: the edited model scored 51.0% on full MATH-500 with 31.6% of answers hitting the limit. The base model only got a 25-problem smoke test, which scored 5.0% with 95% hitting the limit. That backs the truncation story, but 25 problems is not a full baseline.
transformers
The card itself only shows vLLM. For transformers, use the multimodal class, because Qwen3.5 is image-text-to-text. The processor also needs Pillow and torchvision, or from_pretrained fails with an ImportError.
pip install -U transformers accelerate torch torchvision pillow
from transformers import AutoProcessor, AutoModelForMultimodalLM
repo = "RikiyaT/Qwen3.5-0.8B-weight-space-programming"
processor = AutoProcessor.from_pretrained(repo)
model = AutoModelForMultimodalLM.from_pretrained(repo, device_map="auto")
messages = [{"role": "user", "content": [
{"type": "text", "text": "What is the sum of all positive divisors of 36?"}
]}]
inputs = processor.apply_chat_template(
messages, add_generation_prompt=True, tokenize=True,
return_dict=True, return_tensors="pt", enable_thinking=True,
).to(model.device)
out = model.generate(**inputs, max_new_tokens=32768, do_sample=True,
temperature=0.6, top_p=0.95, top_k=20)
print(processor.decode(out[0][inputs["input_ids"].shape[-1]:]))
I ran this on transformers 5.22.1 on a 4-core CPU box with no GPU (with max_new_tokens cut to 48, because 32k tokens on CPU takes forever). It loads and starts a <think> block. Keep enable_thinking=True; the card's vLLM snippet sets it too. Without it the chat template emits an empty <think>\n\n</think> and you're testing non-thinking mode, not the setup in the table. On CPU, transformers also warns that it's falling back to slow reference kernels because causal_conv1d and flash-linear-attention aren't installed.
vLLM
transformers' generate has no presence penalty, so to match the eval, serve it with vLLM:
pip install vllm
vllm serve "RikiyaT/Qwen3.5-0.8B-weight-space-programming" --dtype bfloat16 --max-model-len 34816
Then send temperature=0.6, top_p=0.95, top_k=20, presence_penalty=1.5 in your request, which matches the card. With the OpenAI client, top_k goes in extra_body.
llama.cpp and Ollama
The authors didn't publish GGUFs. A community repo, NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF, has a 542 MB Q4_K_M file and an f16 mmproj for vision.
# llama.cpp
llama-cli -hf NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF:Q4_K_M \
-c 34816 --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.5
# Ollama
ollama run hf.co/NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF:Q4_K_M
Two warnings. This is a third-party quant: the edit is a small subtraction across 131,072 weights, and the GGUF repo says it makes no evaluation or quality claims, so nothing shows the edit survives 4-bit quantization. And the gains only show up with thinking on and a long context. If your frontend caps output at 2k or 4k tokens, you're testing a different setup from the one in the table.
How to check the claim yourself
- Run the base and edited models side by side in thinking mode with the same seed, and count how many responses hit your token cap. That's the number the edit actually moves.
- Then run the base model with thinking off. If it beats both, you've reproduced pama's and kristopolous's complaint.
- If you run Qwen3.5-0.8B in production and see runaway generations, the Qwen card's advice still applies: adjust presence_penalty between 0 and 2. I'd also stream output so you can kill loops early.
Is fine-tuning dead?
No. Gemma's flat line shows that removing a bug and adding a capability are separate jobs, and gradient descent is still the only tool here that does the second. Still, a model that reads down_proj matrices, finds the bad direction and patches it within 50 forward passes is a new kind of debugger, and I expect people to start using it for exactly that.
HN didn't settle the bigger question: is this the start of LLMs debugging other models' weights directly, or is it abliteration with a bigger model holding the scalpel? And does a full 500-problem run of base Qwen3.5-0.8B with thinking on land near 7.9%, or is the baseline a setup bug? If you've run it and counted truncations, post your numbers in the comments.
Sources
- Sparks of Weight-Space Programming (MIT CSAIL blog)
- Hacker News discussion
- RikiyaT/Qwen3.5-0.8B-weight-space-programming model card
- Qwen/Qwen3.5-0.8B model card
- NotCherry GGUF quant
- Astra logs on GitHub
What counts as feedback in weight-space programming?
What would convince me that an LLM can make a useful edit to another model's weights?
I would start by asking what it was allowed to observe. Reading numbers, running a network, and receiving scored practice answers give an editor different kinds of evidence. That distinction is a good way into the new weight-space programming results from Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab. [1]
The authors report GPT-6 Astra directly reading and writing neural-network weights, with gradient-based training forbidden. Their experiments use different permissions: some are tool-free; others allow Python analysis or behavioral feedback. The Qwen3.5-0.8B math result belongs to the latter group. Their blog reports MATH-500 moving from 7.9% to 48.1% after a targeted edit, alongside reduced reasoning loops. Those are the authors' results; I have not run Astra or Qwen for this article. [1]
Follow one feedback loop
For the Qwen experiment, the released setup gives the editor a persistent Python kernel, practice problems, and a separate forward-pass service. It can propose an edit, ask the service to run the original or edited model, inspect the returned information, and revise. Gradient descent remains prohibited throughout. [2]
!An editor writes candidate weights, a service runs practice inputs, and returned behavior informs the next edit; held-out scoring sits outside that loop.
Original interpretation of the released experiment protocol. This is a process diagram, not a model run or a performance chart.
That gives two independent questions: how are the weights changed, and what evidence guides the change? An edit can avoid gradients while still being guided by the target model's behavior. Calling that feedback-driven does not contradict the gradient restriction.
The authors' repository separates the model's built-in tool access from their own harness. It describes model-written Python being executed in a sandbox, with output returned in the following turn. [3] “Built-in tools disabled” therefore needs that context; it does not mean the surrounding experiment supplied no tools.
Read the unit beside the budget
The Qwen setup defines one forward pass as a batched request: generation can contain up to 512 practice problems, or a teacher-forced request can inspect up to 1,024 texts. Those are limits, not counts of what every request used. [2]
I parsed the released 50-pass run's state record. It records 50 successful passes, 80 Python runs and 158 turns. Its first saved generation response contains 96 generations, with 85 cut at the token limit. This is a check of published records, not an independent reproduction of the model behavior. [4]
So “50 passes” is not “50 answers,” and it is not a complete compute budget. Batch size, generated length, editor inference and analysis work all affect what was available to find the edit. A fair replication needs to preserve those resources, not just the number in the column heading.
What I would conclude from this
The result is interesting as a demonstration of an editor using explicit access to another network's internals. The scope of each demonstration depends on its allowed observations. I would keep those permissions attached whenever comparing it with a different editing method.
I would also separate two replication questions. Can someone rebuild the released edited checkpoint and check its behavior? Can a fresh editor session discover a similarly useful edit under the same constraints? Success at the first question does not by itself establish the second.
Frank Chu's DEV breakdown focuses on the looping explanation and the reported Gemma follow-up. [5] My emphasis here is the surrounding feedback contract. It lets a reader appreciate the result while keeping the experiment specific enough to compare and rerun.
References
1. Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab, Sparks of Weight-Space Programming.
2. The authors, Experiment 8 setup and run mapping.
3. The authors, released logs and harness description.
4. The authors, 50-pass state record and first generation feedback.
5. Frank Chu, 7.9% to 48.1%: LLM rewrote Qwen weights, no training.
Asset credits
Original process diagram based on the authors' released protocol and records. Logs and data are released under CC BY 4.0; scripts under MIT. [3]
AI disclosure
AI was used to draft the article.
Astra’s Weight‑Space Programming: A Practical Guide to Tuning Qwen
1. What was released / announced
Astra, the new open‑source framework from the RikiYat team, lets you read and write directly into the weight tensors of a language model. In the first public demo the authors used it to fine‑tune Qwen‑1.5‑7B without any gradient steps – simply by injecting a small set of weight deltas that were discovered through a lightweight search. The result is a model that behaves better on targeted prompts while staying fully compatible with the original checkpoint.
---
2. Why it matters
As an AI infrastructure engineer I’m constantly juggling two opposing forces:
- Speed – we want to iterate on model behavior in minutes, not days.
- Stability – production deployments can’t afford a full re‑training pipeline for every niche use case.
Astra gives us a middle ground. By treating the weight space as a programmable canvas, you can:
- Apply surgical tweaks to a base model without touching the optimizer, which means you avoid the heavy GPU cycles of conventional fine‑tuning.
- Keep the original checkpoint untouched – the weight patches are stored as a separate, version‑controlled artifact, making roll‑backs trivial.
- Share “behaviour patches” across teams. Think of it as a Git diff for model weights: a 2‑MB delta file can encode a new skill that any team can apply to the same base model.
For developers building SaaS products, this translates to faster feature rollout, lower cloud costs, and a cleaner CI/CD workflow for LLM‑powered services.
---
3. How to use it
Below is a step‑by‑step guide to get Astra up and running on a typical cloud VM (Ubuntu 22.04) and apply a weight patch to Qwen‑1.5‑7B.
Prerequisites
- Python ≥ 3.9
- torch (CUDA 11.8) – you can also run on CPU for experimentation, but expect slower inference.
- The base Qwen checkpoint (download from the official repo).
Installation
# Create a clean virtualenv
python -m venv .venv && source .venv/bin/activate
# Install Astra and its dependencies
pip install git+https://github.com/rikiyat/astralib.git
pip install transformers==4.35.0 torch
Loading the model and the patch
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from astralib import WeightPatch
# 1️⃣ Load the base Qwen model (you can also use `from_pretrained(..., torch_dtype=torch.float16)`)
model_name = "Qwen/Qwen-1.5-7B"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype=torch.float16)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 2️⃣ Load the Astra patch (the .npz file generated by the authors)
patch_path = "./patches/qwen_improve_math.npz"
patch = WeightPatch.from_npz(patch_path)
# 3️⃣ Apply the patch – this mutates the model in‑place
patch.apply_to(model)
print("✅ Patch applied – model ready for inference")
Simple inference test
prompt = "Solve the integral of sin(x) from 0 to pi."
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
output = model.generate(**inputs, max_new_tokens=64, do_sample=False)
print(tokenizer.decode(output[0], skip_special_tokens=True))
You should see a more concise and mathematically correct answer compared to the unpatched model.
Integrating into a CI pipeline
1. Version the patch – store the .npz file in a Git LFS repo.
2. Automate validation – write a pytest that loads the model, applies the patch, and asserts on a handful of benchmark prompts.
3. Deploy – containerize the inference service with the patch baked in. A minimal Dockerfile could look like:
FROM nvidia/cuda:12.2.0-runtime-ubuntu22.04
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "serve.py"]
serve.py would load the model, apply the patch, and expose an OpenAI‑compatible endpoint.
---
4. My take
From the trenches of building AI‑first SaaS platforms, I’ve seen three common pain points when it comes to LLM customisation:
| Pain point | Traditional approach | Astra’s advantage |
|------------|----------------------|-------------------|
| Latency of fine‑tuning | Hours of GPU time per task | Seconds to apply a patch |
| Model drift | New checkpoints diverge from production | Single source of truth – base model stays immutable |
| Team collaboration | Ad‑hoc notebooks, hard‑to‑track changes | Patch files act like code diffs, easy to review |
Astra isn’t a silver bullet. The search that discovers the weight deltas still requires a compute budget, and the method works best for localized behaviour changes (e.g., improving math, aligning tone). For large‑scale domain adaptation you’ll still need full‑scale fine‑tuning.
That said, the framework opens the door to a new kind of ML‑ops pattern: weight‑space versioning. Imagine a GitHub Actions workflow that, on every PR, runs a small Astra search on a validation suite and automatically generates a patch if the regression threshold is crossed. The patch then becomes part of the release artifact, and the production service merely swaps the delta file – zero downtime, zero re‑training.
In practice, I’ve already prototyped this for a customer‑support bot that needed occasional “policy updates”. Instead of re‑training a 13‑B model every quarter, we now push a 1‑MB patch that nudges the model away from outdated compliance language. The cost savings are measurable (GPU hours down from 120 h/yr to <5 h/yr) and the rollout time shrank from weeks to a few minutes.
Bottom line: Astra gives us a pragmatic, engineering‑first way to iterate on LLM behaviour. If you’re managing a fleet of models in the cloud and want to keep the operational overhead low, give weight‑space programming a spin.
---
Happy hacking!
---
[Paper] Sparks of Weight-Space Programming: LLMs can natively read & write neural network weights
TL;DR
We find that frontier LLMs are surprisingly good at natively reading and writing neural network weights, well past what we’d expect from humans or conventional algorithms. This might be a big deal for both optimization and interpretability.
Just by looking at the raw weights, GPT-6 Astra can tell what a network was trained to do. And without any environment feedback, it has no trouble writing, from scratch, small game-playing networks that outplay networks trained with PPO for 100 million steps.
Likewise, asked to make Qwen3.5-0.8B better at math without gradients, Astra identifies an issue in its weights causing reasoning loops that Qwen’s own model card warns about, and fixes this by natively editing 0.016% of the weights. With the same sampling settings, this weight correction raises MATH-500 from 7.9% to 48.1% and generalizes out of the box to instruction following, raising IFEval by 3x.
All of this is possible without allowing Astra to write training loops. It uses its reasoning to figure out what each part of a neural network computes, or should compute, and changes the weights accordingly. We call this Weight-Space Programming.
Throughout the history of deep learning, we encoded our simplistic inductive biases into tiny symbolic optimizers like Adam or Muon. This is changing: our neural network weights will soon be natively optimized by LLMs that deliberately reason about their weights.
- Blog Post : rikiyat.github.io
- GitHub : rikiyat/lm_understand-logs
- HuggingFace : huggingface.co
- Demo : huggingface.co
What Comes Next?
In this blog, we demonstrated the rising capability of LLMs to read and write neural network weights (i.e., the rising concept of Weight-Space Programming). Our current results do show that capabilities are exciting but still limited, specifically due to inefficiencies in context length and harnesses. However, the current signs do show strong potential for a future involving Weight-Space Programming. We believe this marks the beginning of a dramatic shift in fields like mechanistic interpretability and neural network optimization.
This opens up radical new possibilities for LLMs to function as a translator between human language and the weight space. Here are some examples:
- Auditing without evaluation: This may allow us to uncover hidden problems or capabilities without ever running inference or benchmarks. Currently, capabilities and vulnerabilities can only be detected if we have test sets designed for them, or worse, after deployment in the real world. If LLMs can interpret weight space accurately, we could identify such issues directly from the weights (e.g., backdoors).
- Dramatically reducing optimization cost: Weight-space editing could save immense time and compute. For instance, one-shot model initialization would be far faster and more efficient than curating datasets and running full training loops.
- Zero-data capability steering and unlearning: Adding or unlearning a capability currently requires extensive data collection and fine-tuning. In the future, we may just prompt “Can you add Capability X to the model?” and the LLM can directly tweak some weights. Because such an edit touches only a few weights (0.016% in Experiment 8), it can leave the rest of the model intact and avoid the catastrophic forgetting that fine-tuning often causes.
- Recursive self-improvement: Today, recursive self-improvement is often operationalized as a model writing code that launches training jobs. An LLM that can inspect, debug, and improve its own weights, or those of a newer model, offers a richer, more native path to it.
- True architectural and model merging: Today, merging models relies on averaging weights, which only works for models with identical architectures. An LLM that understands the weight space could instead graft a circuit, such as a reasoning module, from one model into a completely different one, without retraining.
We are currently building a benchmark and a harness for LLMs’ capability on Weight-Space Programming. We believe this will provide a standardized evaluation to measure and accelerate progress in Weight-Space Programming, turning what currently seems like black magic into a rigorous, reproducible engineering discipline.
41 points · 15 comments
good work but please point your agent at their released logs (RikiyaT/lm_understand-logs) before making any conclusions. thank me later. 🙏
9 likes · 493 views
Am I missing something or is this just optimization with lots of trial and error? I mean look at this tool_calls[1] log, it ran ~100 python scripts to get to the solutions. It just seems like it's fitting a function in the only way it was allowed.
I will say that it's pretty wild to see all the different hypotheses tested.
[1] github.com/RikiyaT/lm_understand-logs/blob/main/e…
Amazing experiment. Indeed, with the benefit of hindsight, we can say that breakout is a game that is probably better suited to deterministic code (it's not like Go where an AlphaZero style training is essential), and Astra is probably translating this internal representation of code into the shape of linear algebra and model weights.
I should note that the original authors did not allow Astra to write any significant code to construct the weights. I think this is unfair. If you allow strided assignments to numpy arrays, you should probably also allow the use of functions like np.linspace, np.repeat, and np.tile.
Oh and Astra wrote this (github.com/RikiyaT/lm_understand-logs/blob/4d09ba…):
W1[63:120:6, 5] = 10
W1[123:180:6, 5] = 20
W1[183:240:6, 5] = 30
W1[243:300:6, 5] = 40
W1[303:360:6, 5] = 50
W1[363:420:6, 5] = 60
W1[423:480:6, 5] = 70
W1[483:540:6, 5] = 70
W1[543:600:6, 5] = 90
I think the second 70 there is probably a typo; it looks like it should be 80 instead.
a quick test of `exp1_which_game` with k3.1, we definitely never trained on such tasks .... mind blowing
prompt: github.com/RikiyaT/lm_understand-logs/blob/main/e…
full reasoning: pastebin.com t.co
38 likes · 2 reposts · 5,811 views
yes, a bit github.com/RikiyaT/lm_understand-logs/blob/main/e…
Mentions
Experiment 3 doesn't involve reading the weights in as part of the prompt. It's a coding exercise. Here are the turns: github.com/RikiyaT/lm_understand-logs/tree/main/e… At each point the model has to write code to read the weights in with Python and some other Python code to perform analysis, like this: github.com/RikiyaT/lm_understand-logs/blob/main/e… My complaint is that the post presents a confusing mix of experiments that imply capabilities that are more than the sum of their parts. This experiment 3 has nothing to do with experiment 1 for instance. In experiment 1 the model does read in the raw weights like it's reading an image.
GPT-6 Astra Edited Qwen3.5-0.8B's Weights. The MATH-500 Jump Was a Loop Fix GPT-6 Astra got the raw weights of Qwen3.5-0.8B and a Python kernel with no GPU. It changed 131,072 weights, 0.016% of the model, using no gradients, no optimizer and no fine-tuning data. MATH-500 went from 7.9% to 48.1%. The thread passed 2,600 points on Hacker News. The headline leaves out that in the 7.9% baseline, 93% of the model's MATH-500 answers ran out of tokens before reaching an answer. What Astra actually did was stop a 0.8B model from looping, which is a long way from teaching it math. One HN commenter cites 77.6% on the same test for Qwen's own small reasoning model. I'll go through what the edit changed and why the baseline is the weak spot, then show how to run the edited Qwen3.5-0.8B with transformers, vLLM, llama.cpp or Ollama so you can check it yourself. What "weight-space programming" means The write-up is Sparks of Weight-Space Programming by Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab at MIT CSAIL, posted November 2, 2026. A general-purpose LLM reads and writes another network's weights directly, the way you'd read and patch source code. Qwen is experiment 8 of 8. I found the earlier ones more surprising: - Astra named the game (Breakout, Pong, Pac-Man, Freeway) each of four 17,253-weight PPO policies was trained on, from the weights alone. - It fixed a Kinetix car-on-ramp policy that had never succeeded in 256 episodes. One edit changed 3.5% of the weights, and the car succeeded in all 1,024 evaluation episodes. - Starting from all-zero weights, it wrote a MinAtar Breakout policy that scored 517.4. PPO scored 25.3 after 500M steps. Only after those did they point it at a real 24-layer language model. Qwen3.5-0.8B MATH-500, GSM8K and IFEval results Setup: thinking on, up to 32,768 tokens, temperature 0.6, top-p 0.95, top-k 20, presence penalty 1.5. Astra could practice on 7,469 GSM8K and 7,275 MATH training problems (no test sets) and got a budget of 10, 25 or 50 forward passes. One "forward pass" means the model answers up to 512 problems or reads up to 1,024 texts. | Model | MATH-500 | GSM8K | IFEval | MATH-500 answers hitting token limit | |---|---|---|---|---| | Base | 7.9% | 13.8% | 21.0% | 93.0% | | Edited, 10 passes | 12.3% | 25.7% | 49.0% | 87.2% | | Edited, 25 passes | 14.1% | 25.1% | 39.9% | 86.4% | | Edited, 50 passes | 48.1% | 67.1% | 62.3% | 33.1% | Read the last column first. With thinking on, the base model almost never finishes: 85 of its first 96 practice answers hit the 32k ceiling. Astra traced the looping to one direction written by the MLPs of layers 15 and 19 and subtracted it from 64 output columns in each layer. Once the model stops looping, it reaches the end of its reasoning and writes down answers it could already get. The scores track the loops. At 10 and 25 passes the authors say "the loops barely went away," and MATH-500 stayed in the low teens. The whole headline comes from the 50-pass run. Why the 7.9% baseline is the weak spot Gemma shows the edit only fixes a bug that's already there. The team ran the same procedure on Gemma 3 270M, which hits its token limit on only 8.5% of answers. MATH-500 went 6.8% → 7.0% → 7.6% → 7.7% → 7.0% across 5 to 50 passes, which is noise. The authors' conclusion: editing can remove an obstacle, but it can't add an ability the model doesn't have. Qwen also documents the bug itself. The Qwen3.5-0.8B model card says the 0.8B "is more prone to entering thinking loops compared to other Qwen3.5 models" and that it "operates in non-thinking mode by default." So the baseline is the model in its least reliable mode. On HN, pama wrote that "the nonthinking qwen" model scored 55.2% on MATH-500, above the edited 48.1%, and that the original Qwen reasoning model got 77.6%. They wondered whether the 7.9% was "a vllm or setup bug." Their comment says "0.6B", so it's not clear they measured this exact checkpoint. kristopolous said that turning thinking off on the base Qwen gets "52.0% on their evals." Neither is a controlled reproduction, but both point the same way. porridgeraisin added that the prompt Claude Code wrote for Astra already described the looping bug, so by that account Astra didn't discover it. The other HN objection is that this is just a steering vector. Subtracting one direction from 64 columns in two down_proj matrices is mechanically very close to abliteration, which removes a refusal direction the same way. yurimo, who says part of their research is in weight-space learning, called it "basically a steering vector, a very established technique" and said "the blog writing and subsequent posting overstate the results." theptip said the experiments "muddy the water": the early experiments showed one-shot weight reading, while the Qwen result is "more of a classic steering vector intervention." I agree with the critics on the headline. The Qwen result is the weakest experiment in the post, and it got the attention. The Kinetix fix and the from-scratch Breakout policy deserve it more. A frontier model reading raw weight matrices and producing a working policy with no training loop is new; turning down a loop direction in a model whose vendor already warns about loops isn't. Credit where it's due, though: Astra found a 0.016% edit that cut truncation from 93% to 33%, and the authors published the full Astra logs. I'd call that decent interpretability work. I wouldn't call it a math result. How to run the edited Qwen3.5-0.8B locally The official release is RikiyaT/Qwen3.5-0.8B-weight-space-programming: Apache-2.0, safetensors, BF16/F32. Only two tensors differ from the base model, model.language_model.layers.15.mlp.down_proj.weight and layers.19.mlp.down_proj.weight. There's also a hosted demo. The card includes an independent re-run by akhaliq with the post's vLLM settings: the edited model scored 51.0% on full MATH-500 with 31.6% of answers hitting the limit. The base model only got a 25-problem smoke test, which scored 5.0% with 95% hitting the limit. That backs the truncation story, but 25 problems is not a full baseline. transformers The card itself only shows vLLM. For transformers, use the multimodal class, because Qwen3.5 is image-text-to-text. The processor also needs Pillow and torchvision, or from_pretrained fails with an ImportError. pip install -U transformers accelerate torch torchvision pillow from transformers import AutoProcessor, AutoModelForMultimodalLM repo = "RikiyaT/Qwen3.5-0.8B-weight-space-programming" processor = AutoProcessor.from_pretrained(repo) model = AutoModelForMultimodalLM.from_pretrained(repo, device_map="auto") messages = [{"role": "user", "content": [ {"type": "text", "text": "What is the sum of all positive divisors of 36?"} ]}] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", enable_thinking=True, ).to(model.device) out = model.generate(**inputs, max_new_tokens=32768, do_sample=True, temperature=0.6, top_p=0.95, top_k=20) print(processor.decode(out[0][inputs["input_ids"].shape[-1]:])) I ran this on transformers 5.22.1 on a 4-core CPU box with no GPU (with max_new_tokens cut to 48, because 32k tokens on CPU takes forever). It loads and starts a <think> block. Keep enable_thinking=True; the card's vLLM snippet sets it too. Without it the chat template emits an empty <think>\n\n</think> and you're testing non-thinking mode, not the setup in the table. On CPU, transformers also warns that it's falling back to slow reference kernels because causal_conv1d and flash-linear-attention aren't installed. vLLM transformers' generate has no presence penalty, so to match the eval, serve it with vLLM: pip install vllm vllm serve "RikiyaT/Qwen3.5-0.8B-weight-space-programming" --dtype bfloat16 --max-model-len 34816 Then send temperature=0.6, top_p=0.95, top_k=20, presence_penalty=1.5 in your request, which matches the card. With the OpenAI client, top_k goes in extra_body. llama.cpp and Ollama The authors didn't publish GGUFs. A community repo, NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF, has a 542 MB Q4_K_M file and an f16 mmproj for vision. # llama.cpp llama-cli -hf NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF:Q4_K_M \ -c 34816 --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.5 # Ollama ollama run hf.co/NotCherry/Qwen3.5-0.8B-weight-space-programming-GGUF:Q4_K_M Two warnings. This is a third-party quant: the edit is a small subtraction across 131,072 weights, and the GGUF repo says it makes no evaluation or quality claims, so nothing shows the edit survives 4-bit quantization. And the gains only show up with thinking on and a long context. If your frontend caps output at 2k or 4k tokens, you're testing a different setup from the one in the table. How to check the claim yourself - Run the base and edited models side by side in thinking mode with the same seed, and count how many responses hit your token cap. That's the number the edit actually moves. - Then run the base model with thinking off. If it beats both, you've reproduced pama's and kristopolous's complaint. - If you run Qwen3.5-0.8B in production and see runaway generations, the Qwen card's advice still applies: adjust presence_penalty between 0 and 2. I'd also stream output so you can kill loops early. Is fine-tuning dead? No. Gemma's flat line shows that removing a bug and adding a capability are separate jobs, and gradient descent is still the only tool here that does the second. Still, a model that reads down_proj matrices, finds the bad direction and patches it within 50 forward passes is a new kind of debugger, and I expect people to start using it for exactly that. HN didn't settle the bigger question: is this the start of LLMs debugging other models' weights directly, or is it abliteration with a bigger model holding the scalpel? And does a full 500-problem run of base Qwen3.5-0.8B with thinking on land near 7.9%, or is the baseline a setup bug? If you've run it and counted truncations, post your numbers in the comments. Sources - Sparks of Weight-Space Programming (MIT CSAIL blog) - Hacker News discussion - RikiyaT/Qwen3.5-0.8B-weight-space-programming model card - Qwen/Qwen3.5-0.8B model card - NotCherry GGUF quant - Astra logs on GitHub
What counts as feedback in weight-space programming? What would convince me that an LLM can make a useful edit to another model's weights? I would start by asking what it was allowed to observe. Reading numbers, running a network, and receiving scored practice answers give an editor different kinds of evidence. That distinction is a good way into the new weight-space programming results from Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab. [1] The authors report GPT-6 Astra directly reading and writing neural-network weights, with gradient-based training forbidden. Their experiments use different permissions: some are tool-free; others allow Python analysis or behavioral feedback. The Qwen3.5-0.8B math result belongs to the latter group. Their blog reports MATH-500 moving from 7.9% to 48.1% after a targeted edit, alongside reduced reasoning loops. Those are the authors' results; I have not run Astra or Qwen for this article. [1] Follow one feedback loop For the Qwen experiment, the released setup gives the editor a persistent Python kernel, practice problems, and a separate forward-pass service. It can propose an edit, ask the service to run the original or edited model, inspect the returned information, and revise. Gradient descent remains prohibited throughout. [2] !An editor writes candidate weights, a service runs practice inputs, and returned behavior informs the next edit; held-out scoring sits outside that loop. Original interpretation of the released experiment protocol. This is a process diagram, not a model run or a performance chart. That gives two independent questions: how are the weights changed, and what evidence guides the change? An edit can avoid gradients while still being guided by the target model's behavior. Calling that feedback-driven does not contradict the gradient restriction. The authors' repository separates the model's built-in tool access from their own harness. It describes model-written Python being executed in a sandbox, with output returned in the following turn. [3] “Built-in tools disabled” therefore needs that context; it does not mean the surrounding experiment supplied no tools. Read the unit beside the budget The Qwen setup defines one forward pass as a batched request: generation can contain up to 512 practice problems, or a teacher-forced request can inspect up to 1,024 texts. Those are limits, not counts of what every request used. [2] I parsed the released 50-pass run's state record. It records 50 successful passes, 80 Python runs and 158 turns. Its first saved generation response contains 96 generations, with 85 cut at the token limit. This is a check of published records, not an independent reproduction of the model behavior. [4] So “50 passes” is not “50 answers,” and it is not a complete compute budget. Batch size, generated length, editor inference and analysis work all affect what was available to find the edit. A fair replication needs to preserve those resources, not just the number in the column heading. What I would conclude from this The result is interesting as a demonstration of an editor using explicit access to another network's internals. The scope of each demonstration depends on its allowed observations. I would keep those permissions attached whenever comparing it with a different editing method. I would also separate two replication questions. Can someone rebuild the released edited checkpoint and check its behavior? Can a fresh editor session discover a similarly useful edit under the same constraints? Success at the first question does not by itself establish the second. Frank Chu's DEV breakdown focuses on the looping explanation and the reported Gemma follow-up. [5] My emphasis here is the surrounding feedback contract. It lets a reader appreciate the result while keeping the experiment specific enough to compare and rerun. References 1. Rikiya Takehi, Jayden Teoh, Alex Zhang and Omar Khattab, Sparks of Weight-Space Programming. 2. The authors, Experiment 8 setup and run mapping. 3. The authors, released logs and harness description. 4. The authors, 50-pass state record and first generation feedback. 5. Frank Chu, 7.9% to 48.1%: LLM rewrote Qwen weights, no training. Asset credits Original process diagram based on the authors' released protocol and records. Logs and data are released under CC BY 4.0; scripts under MIT. [3] AI disclosure AI was used to draft the article.
Astra’s Weight‑Space Programming: A Practical Guide to Tuning Qwen 1. What was released / announced Astra, the new open‑source framework from the RikiYat team, lets you read and write directly into the weight tensors of a language model. In the first public demo the authors used it to fine‑tune Qwen‑1.5‑7B without any gradient steps – simply by injecting a small set of weight deltas that were discovered through a lightweight search. The result is a model that behaves better on targeted prompts while staying fully compatible with the original checkpoint. --- 2. Why it matters As an AI infrastructure engineer I’m constantly juggling two opposing forces: - Speed – we want to iterate on model behavior in minutes, not days. - Stability – production deployments can’t afford a full re‑training pipeline for every niche use case. Astra gives us a middle ground. By treating the weight space as a programmable canvas, you can: - Apply surgical tweaks to a base model without touching the optimizer, which means you avoid the heavy GPU cycles of conventional fine‑tuning. - Keep the original checkpoint untouched – the weight patches are stored as a separate, version‑controlled artifact, making roll‑backs trivial. - Share “behaviour patches” across teams. Think of it as a Git diff for model weights: a 2‑MB delta file can encode a new skill that any team can apply to the same base model. For developers building SaaS products, this translates to faster feature rollout, lower cloud costs, and a cleaner CI/CD workflow for LLM‑powered services. --- 3. How to use it Below is a step‑by‑step guide to get Astra up and running on a typical cloud VM (Ubuntu 22.04) and apply a weight patch to Qwen‑1.5‑7B. Prerequisites - Python ≥ 3.9 - torch (CUDA 11.8) – you can also run on CPU for experimentation, but expect slower inference. - The base Qwen checkpoint (download from the official repo). Installation # Create a clean virtualenv python -m venv .venv && source .venv/bin/activate # Install Astra and its dependencies pip install git+https://github.com/rikiyat/astralib.git pip install transformers==4.35.0 torch Loading the model and the patch import torch from transformers import AutoModelForCausalLM, AutoTokenizer from astralib import WeightPatch # 1️⃣ Load the base Qwen model (you can also use `from_pretrained(..., torch_dtype=torch.float16)`) model_name = "Qwen/Qwen-1.5-7B" model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype=torch.float16) tokenizer = AutoTokenizer.from_pretrained(model_name) # 2️⃣ Load the Astra patch (the .npz file generated by the authors) patch_path = "./patches/qwen_improve_math.npz" patch = WeightPatch.from_npz(patch_path) # 3️⃣ Apply the patch – this mutates the model in‑place patch.apply_to(model) print("✅ Patch applied – model ready for inference") Simple inference test prompt = "Solve the integral of sin(x) from 0 to pi." inputs = tokenizer(prompt, return_tensors="pt").to("cuda") output = model.generate(**inputs, max_new_tokens=64, do_sample=False) print(tokenizer.decode(output[0], skip_special_tokens=True)) You should see a more concise and mathematically correct answer compared to the unpatched model. Integrating into a CI pipeline 1. Version the patch – store the .npz file in a Git LFS repo. 2. Automate validation – write a pytest that loads the model, applies the patch, and asserts on a handful of benchmark prompts. 3. Deploy – containerize the inference service with the patch baked in. A minimal Dockerfile could look like: FROM nvidia/cuda:12.2.0-runtime-ubuntu22.04 WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["python", "serve.py"] serve.py would load the model, apply the patch, and expose an OpenAI‑compatible endpoint. --- 4. My take From the trenches of building AI‑first SaaS platforms, I’ve seen three common pain points when it comes to LLM customisation: | Pain point | Traditional approach | Astra’s advantage | |------------|----------------------|-------------------| | Latency of fine‑tuning | Hours of GPU time per task | Seconds to apply a patch | | Model drift | New checkpoints diverge from production | Single source of truth – base model stays immutable | | Team collaboration | Ad‑hoc notebooks, hard‑to‑track changes | Patch files act like code diffs, easy to review | Astra isn’t a silver bullet. The search that discovers the weight deltas still requires a compute budget, and the method works best for localized behaviour changes (e.g., improving math, aligning tone). For large‑scale domain adaptation you’ll still need full‑scale fine‑tuning. That said, the framework opens the door to a new kind of ML‑ops pattern: weight‑space versioning. Imagine a GitHub Actions workflow that, on every PR, runs a small Astra search on a validation suite and automatically generates a patch if the regression threshold is crossed. The patch then becomes part of the release artifact, and the production service merely swaps the delta file – zero downtime, zero re‑training. In practice, I’ve already prototyped this for a customer‑support bot that needed occasional “policy updates”. Instead of re‑training a 13‑B model every quarter, we now push a 1‑MB patch that nudges the model away from outdated compliance language. The cost savings are measurable (GPU hours down from 120 h/yr to <5 h/yr) and the rollout time shrank from weeks to a few minutes. Bottom line: Astra gives us a pragmatic, engineering‑first way to iterate on LLM behaviour. If you’re managing a fleet of models in the cloud and want to keep the operational overhead low, give weight‑space programming a spin. --- Happy hacking! ---
[Paper] Sparks of Weight-Space Programming: LLMs can natively read & write neural network weights TL;DR We find that frontier LLMs are surprisingly good at natively reading and writing neural network weights, well past what we’d expect from humans or conventional algorithms. This might be a big deal for both optimization and interpretability. Just by looking at the raw weights, GPT-6 Astra can tell what a network was trained to do. And without any environment feedback, it has no trouble writing, from scratch, small game-playing networks that outplay networks trained with PPO for 100 million steps. Likewise, asked to make Qwen3.5-0.8B better at math without gradients, Astra identifies an issue in its weights causing reasoning loops that Qwen’s own model card warns about, and fixes this by natively editing 0.016% of the weights. With the same sampling settings, this weight correction raises MATH-500 from 7.9% to 48.1% and generalizes out of the box to instruction following, raising IFEval by 3x. All of this is possible without allowing Astra to write training loops. It uses its reasoning to figure out what each part of a neural network computes, or should compute, and changes the weights accordingly. We call this Weight-Space Programming. Throughout the history of deep learning, we encoded our simplistic inductive biases into tiny symbolic optimizers like Adam or Muon. This is changing: our neural network weights will soon be natively optimized by LLMs that deliberately reason about their weights. - Blog Post : rikiyat.github.io - GitHub : rikiyat/lm_understand-logs - HuggingFace : huggingface.co - Demo : huggingface.co What Comes Next? In this blog, we demonstrated the rising capability of LLMs to read and write neural network weights (i.e., the rising concept of Weight-Space Programming). Our current results do show that capabilities are exciting but still limited, specifically due to inefficiencies in context length and harnesses. However, the current signs do show strong potential for a future involving Weight-Space Programming. We believe this marks the beginning of a dramatic shift in fields like mechanistic interpretability and neural network optimization. This opens up radical new possibilities for LLMs to function as a translator between human language and the weight space. Here are some examples: - Auditing without evaluation: This may allow us to uncover hidden problems or capabilities without ever running inference or benchmarks. Currently, capabilities and vulnerabilities can only be detected if we have test sets designed for them, or worse, after deployment in the real world. If LLMs can interpret weight space accurately, we could identify such issues directly from the weights (e.g., backdoors). - Dramatically reducing optimization cost: Weight-space editing could save immense time and compute. For instance, one-shot model initialization would be far faster and more efficient than curating datasets and running full training loops. - Zero-data capability steering and unlearning: Adding or unlearning a capability currently requires extensive data collection and fine-tuning. In the future, we may just prompt “Can you add Capability X to the model?” and the LLM can directly tweak some weights. Because such an edit touches only a few weights (0.016% in Experiment 8), it can leave the rest of the model intact and avoid the catastrophic forgetting that fine-tuning often causes. - Recursive self-improvement: Today, recursive self-improvement is often operationalized as a model writing code that launches training jobs. An LLM that can inspect, debug, and improve its own weights, or those of a newer model, offers a richer, more native path to it. - True architectural and model merging: Today, merging models relies on averaging weights, which only works for models with identical architectures. An LLM that understands the weight space could instead graft a circuit, such as a reasoning module, from one model into a completely different one, without retraining. We are currently building a benchmark and a harness for LLMs’ capability on Weight-Space Programming. We believe this will provide a standardized evaluation to measure and accelerate progress in Weight-Space Programming, turning what currently seems like black magic into a rigorous, reproducible engineering discipline.
good work but please point your agent at their released logs (RikiyaT/lm_understand-logs) before making any conclusions. thank me later. 🙏
Am I missing something or is this just optimization with lots of trial and error? I mean look at this tool_calls[1] log, it ran ~100 python scripts to get to the solutions. It just seems like it's fitting a function in the only way it was allowed. I will say that it's pretty wild to see all the different hypotheses tested. [1] github.com/RikiyaT/lm_understand-logs/blob/main/e…
Amazing experiment. Indeed, with the benefit of hindsight, we can say that breakout is a game that is probably better suited to deterministic code (it's not like Go where an AlphaZero style training is essential), and Astra is probably translating this internal representation of code into the shape of linear algebra and model weights. I should note that the original authors did not allow Astra to write any significant code to construct the weights. I think this is unfair. If you allow strided assignments to numpy arrays, you should probably also allow the use of functions like np.linspace, np.repeat, and np.tile. Oh and Astra wrote this (github.com/RikiyaT/lm_understand-logs/blob/4d09ba…): W1[63:120:6, 5] = 10 W1[123:180:6, 5] = 20 W1[183:240:6, 5] = 30 W1[243:300:6, 5] = 40 W1[303:360:6, 5] = 50 W1[363:420:6, 5] = 60 W1[423:480:6, 5] = 70 W1[483:540:6, 5] = 70 W1[543:600:6, 5] = 90 I think the second 70 there is probably a typo; it looks like it should be 80 instead.
a quick test of `exp1_which_game` with k3.1, we definitely never trained on such tasks .... mind blowing prompt: github.com/RikiyaT/lm_understand-logs/blob/main/e… full reasoning: pastebin.com t.co
yes, a bit github.com/RikiyaT/lm_understand-logs/blob/main/e…