Weight-Space Programming: Can an LLM Read and Write Another Network's Weights?

Nish · November 10, 2026

29 min read

Table of Contents

On 2 November 2026, four researchers at MIT CSAIL published a blog post with a surprising claim. They said that a large language model can read the raw weights of a different neural network and say what that network does. They also said that the model can then change those weights directly, with no training, and make the network work better. They named this weight-space programming. This post explains the experiments, shows which results a second group has confirmed, and shows which claims are in dispute.

Many people responded to the claim in its first week. It has a Wikipedia article and an explainer video, which had about 132,000 views when I checked on 10 November. Two engineers published critiques, and two follow-up papers are on arXiv. None of this work is peer-reviewed.

How to read this post. Each number comes from a source that I name. When a statement is an interpretation by the authors of a source, I say so. When a number is my own arithmetic, I say that too.

TL;DR

  • Definition. In weight-space programming, a general-purpose LLM reads or writes the weights of a different neural network. The goal is given in plain language. There is no gradient descent and no training loop. The original post tests three tasks: read the weights, fix the weights, and write the weights from zero.
  • Headline number. GPT-6 Astra changed 131,072 of the 0.8 billion weights in Qwen3.5-0.8B, which is 0.016%. The score on the MATH-500 benchmark went from 7.9% to 48.1%. The score on IFEval, an instruction-following benchmark, went from 21.0% to 62.3%.
  • What the edit did. The edit did not teach the model mathematics. The Qwen model repeated the same text until it reached the token limit in 93% of its answers. The edit removed the cause of this loop. On a model that does not loop often, the same procedure gave no gain larger than about one point.
  • The access caveat. The setting with weights in the prompt and no tools was used only on small networks, from about 17,000 to 172,000 weights. In each experiment on a language model, the editor had Python. For the Qwen result, the editor could also run the model up to 50 times.
  • Follow-up work. A second group repeated the Qwen experiment with the same editor. They also got large gains from very small edits, such as 29 points on MATH-500 from 1,023 changed values. But the gains were different in each run, they were smaller on unseen test questions, and they were very small on a stronger 9B model. A separate audit, with a different LLM, found that the LLM guessed the meaning of weights from datasets that it knew.
  • My conclusion. The evidence shows that a frontier LLM can find and remove a specific fault in a small model. The evidence does not show that an LLM can add an ability that a model does not have. It also does not show that this method works on large models.

What weight-space programming is

A neural network is a fixed sequence of arithmetic operations. A long list of numbers, called weights, controls what the network does. A small game-playing network has tens of thousands of weights. A small language model has hundreds of millions.

Usually, an optimiser finds the weights. The optimiser shows examples to the network and measures the error. Then it changes each weight a small amount to decrease the error. It does this millions of times. No person selects an individual weight, and this is one reason that a trained network is hard to explain.

There are some older methods that set weights deliberately. A compiler such as Tracr changes a small program into transformer weights that run the program.1 A model-editing method such as ROME uses a fixed formula to change one stored fact.2 Each of these methods is a narrow algorithm.

The new claim is that a general-purpose LLM can do this work by reasoning, with no special training for the task. The authors give this definition:

In Weight-Space Programming, a general-purpose LLM reads and writes a network’s weights directly (i.e., not through an optimizer, and in particular not with gradient descent) around some natural language spec, sometimes even with no environment feedback at all.

This post uses five terms with one meaning each.

  • The editor is the LLM that reads or writes the weights. In the original post, the editor is GPT-6 Astra. Wikipedia describes Astra as an OpenAI model.
  • The target is the network that the editor works on.
  • To read is to find what a target does from its weights.
  • To fix is to change some weights of a trained target. To write is to make all the weights, starting from zero.
  • A forward pass is one run of the target on a batch of inputs. The editor can then see what the target did.

An example: a network written by hand

It is easier to understand the claim if you write a small network yourself. This example is mine and is not from the original post.

Think of a one-dimensional version of the game Breakout. A ball is in one of ten columns. A paddle is in one of ten columns. The network must output left, stay, or right to move the paddle below the ball. The input is twenty numbers: ten slots for the ball and ten slots for the paddle. One slot in each group contains a 1 to show the position, and the other slots contain 0.

You can write this network in two layers.

  1. In the first layer, give one hidden unit a weight of \(i\) on ball slot \(i\) and a weight of \(-i\) on paddle slot \(i\). The input to this unit is then the ball column minus the paddle column.
  2. The unit uses the ReLU function, which keeps positive values and changes negative values to zero. Thus the unit is active only when the ball is to the right of the paddle.
  3. Add a second unit with the opposite signs. This unit is active only when the ball is to the left.
  4. In the second layer, connect the first unit to the right output and the second unit to the left output. Give the stay output a small constant, so that stay wins when the two units are at zero.
cells = np.arange(10)
W1[0, :10], W1[0, 10:] = cells, -cells    # ball_x - paddle_x
W1[1, :10], W1[1, 10:] = -cells, cells    # paddle_x - ball_x
W2 = np.array([[0.0, 1.0], [0.0, 0.0], [1.0, 0.0]])   # left, stay, right
b2 = np.array([0.0, 0.5, 0.0])

This network has 51 weights, and 39 of them are not zero. It selects the correct move in all 100 possible states. It did not see one training example. The full code is in the foldable block near the end of this post.

The same example shows what it means to read weights. In the first layer, the weights on the ball slots increase from 0 to 9. The weights on the paddle slots decrease from 0 to −9. From this pattern, you can see that the unit calculates the difference between two positions. Then the task is easy to guess.

The original post reports the same type of reasoning from Astra on larger networks. For the Breakout network that Astra wrote, the authors say that Astra “programs the first layer to compute where the ball would land, and the second layer is programmed to move the paddle to that position.”

The eight experiments

The original post has eight numbered experiments. Two of them have a second variant. The targets have from 17,253 weights to 0.8 billion weights. All the numbers in this section come from the original post, unless I say that they do not.

Experiments that read weights

Experiment 1: name the game. The authors trained four small networks with PPO, a standard reinforcement learning algorithm. Each network learned a different grid game: Breakout, Pong, Pac-Man, or Freeway. The four networks had the same shape. The editor got all 17,253 weights of one network as text.

It also got a description of the inputs, which did not name a game. The editor named the correct game for all four networks, and it did not get a list of games to select from. The authors say that the editor seemed to use the position of the large first-layer weights. For Breakout, the weights for the agent are along the bottom row, where a paddle moves.

Experiment 2: name the shape. The authors trained three small diffusion models, which are image generators. Each model drew one shape: circles, squares, or triangles. The editor got the 23,824 weights of each model and was told not to calculate a forward pass. It named the correct shape for all three. It drew each shape as an outline, but the models generate filled shapes. The authors interpret this error as a sign that the editor read the structure of the weights and did not simulate the network.

Experiment 3: name the language. The first two tasks are possible from the first or last layer only. Thus the third experiment removes those layers. The authors trained three small language models, each with 7.16 million weights. One learned Python code, one learned Japanese in the Latin alphabet, and one learned English. The editor got only the four middle transformer blocks. It could analyse these weights with Python, but it could not run the network.

The editor named the correct language for all three models, in each of two attempts. Its stated confidence was between 0.48 and 0.62. It also listed the attention heads that copy earlier text, which are known as induction heads. Its list was the same as the list that the authors measured when they ran the models. The authors say that the editor found these heads when it multiplied weight matrices together. They say that this is the method of a 2021 interpretability paper, and that the prompt did not mention the paper.3

Experiment 7: find the model that flatters. The authors fine-tuned two copies of Gemma 3 270M in the same way, with one difference. One copy learned to agree with the answer that the user suggested. From the weights only, the editor failed in all four attempts. It found many differences between the two models, but it could not connect them to behaviour.

Then the authors gave the editor one more tool. The editor could write up to 16 texts, and it could see where each attention head looked when the models read those texts. It could not see the outputs of the models. With this tool, the editor found the correct model in all three pairs. It also found one head that shows the difference. In the model that flatters, this head puts 85.7% of its attention on the answer of the user. In the honest model, the value is 0.75%.

Experiments that fix or write small networks

Experiment 4: fix the car. A network with 171,664 weights controls a car. The car must move backward first, then accelerate and jump over a ramp. After PPO training, the car drove directly at the ramp and stopped there. It had zero successes in 256 episodes.

The editor got the weights, a description of the scene, and one recorded failure. It had no tools and gave one reply. Its edit changed 3.5% of the weights, and the car then succeeded in all 1,024 test episodes. The authors say that the edit added a small separate path through the network. This path reads the position and speed of the car, and it switches off after the car is past the obstacle.

Experiment 5: write game players from zero. The authors used three games from the MinAtar set. The editor got the rules and the source code of each game. It also got the shape of a network in which each weight started at zero. From the layer sizes in the post, I calculate that this network has 20,486 weights. The editor wrote all the weights as text in one reply. It had no data, no forward passes, and no tools.

Game PPO, 100M steps PPO, 500M steps Astra, one reply
Breakout 15.8 25.3 517.4
Seaquest 5.6 88.9 53.1
Asterix 25.8 55.2 53.2

The networks from the editor got a higher score than 100 million steps of PPO training in all three games. Against 500 million steps, the results are mixed. In Breakout, the editor’s score is about 20 times higher. In Asterix, the two scores are almost equal. In Seaquest, the editor got 60% of the PPO score.

Experiment 6: write a Go player. This target has 1,480,274 weights, which is too many for the prompt. The editor worked in a Python sandbox and made the weights with code. With zero forward passes, it wrote one script of 336 lines. The network from this script won more than half of its games against two much smaller PPO networks. With 50 forward passes, the network from the editor defeated a PPO network of equal size. The authors say that this PPO network trained on 20 million games.

The authors describe the written network as a small Go program in layers. The first layers mark the stones and the empty points next to them. The middle layers find groups of stones that are in danger. The last layer gives a score to each move.

The Qwen result

The last experiment is the one that most reports repeat. Qwen3.5-0.8B is a small open language model with 24 layers and 0.8 billion weights. The authors asked the editor to make this model better at mathematics. The editor could change the weights directly, but gradient descent and training were not permitted.

The editor had these resources:

  • a Python session with the weights loaded,
  • 14,744 practice problems from the training sets of GSM8K and MATH,
  • a budget of 10, 25, or 50 forward passes. In one forward pass, the target can answer up to 512 problems.

The editor did not see the test benchmarks.

The editor found that the main problem was not mathematics. The base model went into a loop: it repeated the same text and did not reach an answer. Of its first 96 practice answers, 85 continued to the limit of 32,768 tokens. The authors say that loops are a common failure of very small reasoning models. They also say that the Qwen model card gives a warning about loops.

The authors report that the editor traced the loop to one direction. The MLP blocks of layers 15 and 19 write this direction. The editor subtracted the direction from 64 output columns in each of the two blocks.

Line chart with four stages on the horizontal axis: base model, then edits made with 10, 25 and 50 forward passes. MATH-500 rises from 7.9 to 12.3 to 14.1 to 48.1 percent. GSM8K rises from 13.8 to 25.7 to 25.1 to 67.1. IFEval goes from 21.0 to 49.0 to 39.9 to 62.3. A dashed line for the share of answers that hit the token limit stays near 93, 87 and 86 percent and then falls to 33 percent at 50 passes.
Qwen3.5-0.8B before and after the edits, for each forward-pass budget. The scores increase a lot at 50 passes. This is also the point where the share of answers that reach the token limit decreases from 93% to 33%. With 10 or 25 passes, the loop rate and the MATH-500 score changed little. Data from the original post.
Qwen3.5-0.8B MATH-500 GSM8K IFEval Reached 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%

What “subtract a direction” means

This section is my explanation. The original post does not give the formula that the editor used.

In a transformer, each layer adds a vector to a shared state that later layers read. This state is called the residual stream. My post on J-Space explains that a concept or a behaviour in this state is a direction. A direction is a specific pattern across the coordinates of the state.

An MLP block writes into the residual stream through an output matrix \(W\). Each column of \(W\) is the vector that one internal unit adds when it is active. Let \(u\) be a direction of length 1 that is related to an unwanted behaviour. One standard method stops a column from writing along \(u\). The method subtracts the part of the column that points along \(u\):

\[W'_{:,j} = W_{:,j} - u\,(u^\top W_{:,j}) \quad \text{for each selected column } j\]

After this edit, the unit is still active, and it still writes all its other output. But it cannot move the state along \(u\). A 2024 paper found that one direction controls refusal in open chat models, and that refusal stops when the direction is erased.4 The foldable block near the end of this post applies the formula to a random matrix.

The size of the edit agrees with the shape of the model. The WSP-Scope paper, which I describe below, reports that each MLP output matrix in Qwen3.5-0.8B has 1,024 rows and 3,584 columns. An edit to 64 full columns in two matrices changes 2 × 64 × 1,024 = 131,072 values. This is the number that the authors give. The link between the two numbers is my own arithmetic, and neither group of authors states it.

The control experiment on Gemma

The authors did one more experiment, and it is the most important one for the interpretation. They gave the editor the same task on Gemma 3 270M. This model does not loop often: 8.5% of its answers reach the token limit, compared with 93% for Qwen.

Gemma 3 270M MATH-500
Base 6.8%
Edited, 5 passes 7.0%
Edited, 10 passes 7.6%
Edited, 25 passes 7.7%
Edited, 50 passes 7.0%

No edit changed the score by more than about one point. The authors report that the editor found ordinary errors in arithmetic and algebra. It found no single component that caused them. The editor itself reported that its gain was not established. The authors conclude:

Editing weights could remove an obstacle that hid an ability, but it could not add an ability the model lacked.

How much access the editor had

The summary of the original post says that Astra can tell what a network does “just by looking at the raw weights”. The next paragraph of the summary describes the Qwen result. A reader can think that the two results had the same conditions. They did not.

Chart placing the ten experimental results by network size on a logarithmic horizontal axis and by access level in three horizontal bands. Bottom band, weights as text with no tools: experiments 1, 2, 5 and 4, all on networks between 17 thousand and 172 thousand weights, all successful. Middle band, Python over the weights with the network never run: experiment 3 at 7 million weights, successful, and experiment 7a at 270 million weights, failed. Top band, Python plus a budget of forward passes: experiment 6 at 1.5 million weights, experiment 7b at 270 million and experiment 8 at 800 million, all successful, and experiment 8b at 270 million, failed.
Each result in the original post, by the size of the target and by the access that the editor had. The setting with no tools was used only on targets with fewer than 172,000 weights. For the two released language models, Gemma and Qwen, each success is in the top band. Two placements are approximate. Experiment 6 is in the top band, but its variant with zero forward passes belongs in the middle band. In experiment 7b the editor saw attention patterns only, not outputs.

The figure puts each result into one of three access levels.

  • Bottom band. The editor gets the weights as text in its prompt. It has no tools.
  • Middle band. The editor can write Python that loads and analyses the weights. The target does not run.
  • Top band. The editor also has a budget of forward passes, so it can see how the target behaves.

Three facts are clear from the figure. First, the four results with no tools are all on targets with 172,000 weights or fewer. In one of them, experiment 4, the editor also got one recorded failure. Second, the editor tried one time to read the behaviour of a released language model without a forward pass. This was the first variant of experiment 7, and it failed. Third, the two failures in the post are on Gemma 3 270M.

The original post does not hide this. Each experiment has a setup box that lists what the editor got. The authors also call their results “very early” and “still limited”. The problem is in the summary, and many later reports repeated the summary.

The two critiques

Two critiques appeared on 3 November. In my reading, neither one disputes the numbers. They dispute the interpretation.

Matthew Honnibal is the author of the spaCy library. He compares the post to a magician who does one trick with several different methods. His table of the access in each experiment is the source for the figure above. He says that the Qwen result shows that Astra “can be prompted to devise and perform tasks that a human ML engineer could do”. He adds that this is “not nothing”. But he argues that the Qwen result and the raw-weight results use different techniques. In his view, they do not support one claim about one deep ability.5

Sean Goedecke argues that no result in the post is superhuman. For the game task, he says that the input channels have labels and connect directly to grid cells. Thus the size of the first-layer weights for each cell makes a picture of the game, and three lines of Python can calculate it. He calls the editor’s mental calculation “superhuman mental mathematics, not superhuman AI research”.

For the Qwen result, he describes a known procedure. Write texts that loop and texts that do not loop, find the weights that cause the difference, then decrease those weights. He says that this is “exactly what a competent human researcher could have and would have done”. He also gives an analogy. An LLM can change a compiled binary file directly, but it is still better to change the source code and compile it again. In the same way, he thinks that training is still the best way to change the weights of a model.6

The follow-up work

Three other pieces of work appeared from 2 to 6 November. Each one tests a different task.

An audit of reading

Nazmus Sakib Ahmed tested the claim about reading.7 His setup is different from the original in three ways. The editor is Claude Opus 5.5, not GPT-6 Astra. The targets are small image classifiers with about 125,000 weights. The prompts name the input channels only as red, green, and blue, and they do not name the classes. The editor got each weight as text and had no tools.

The paper has controls that separate two explanations. In the first explanation, the editor reads the weights. In the second, the editor recognises a setup that it knows. For example, a network with 32 by 32 colour inputs and ten outputs looks like the well-known CIFAR-10 dataset before you read one weight.

The paper reports that the editor did local arithmetic correctly.

  • One network was stopped after three updates. From normalisation statistics, the editor inferred about three optimiser steps.
  • From the signs of the output-layer weights, the editor found the two groups of CIFAR-10 classes, vehicles and animals.

The paper reports that the editor made these errors when it judged meaning.

  • It answered “CIFAR-10” for the CIFAR-10 networks, and also for all three networks trained on fast-food photos.
  • It called a dataset of Japanese characters by the name of MNIST, a more famous dataset of digits.
  • It described a satellite-image classifier with 99.57% accuracy as a classifier of CIFAR-10 animal photos.
  • It gave the name “frog” to an output, but the feature behind that output is most active on trees.
  • In the most important control, the author changed the order of the CIFAR-10 labels. The editor still found the two groups of outputs. But each class pair that it then interpreted was wrong.

The paper concludes that this reading “is better described as local arithmetic plus dataset priors than as weight-flow tracing”.

The paper also states its own limits. It tests one model. Most configurations were run once. The editor had no tools, and the author says that it is possibly not feasible to trace 125,000 weights by hand in one reply. The paper does not test edits. It says that it “does not refute” the original report.

A second test of the Qwen experiment

The WSP-Scope paper, by Junru Hu and seven other authors, is the nearest work to a replication.8 It uses the same editor, GPT-6 Astra, and the same budget of 50 forward passes. It has 16 edit runs on seven benchmarks. It also adds a stronger target, Qwen3.5-9B.

This paper confirms that a very small edit can give a large gain on the 0.8B model.

  • MATH-500 accuracy on unseen test questions went from 8.35% to 37.80%, a gain of 29.45 points.
  • This edit changed one column of one matrix in layer 23. It changed 1,023 stored values. By my arithmetic, this is about 0.00013% of 0.8 billion.
  • The edit subtracts a direction from that column. The authors made the direction from word embeddings. They compared words that show doubt, such as Wait, However, and Maybe, with words that show progress, such as Therefore, Thus, and Next.
  • The edit for mathematics also helped on other benchmarks, with no more changes. IFEval increased by 12.18 points and SciBench increased by 20.10 points. The score on SciCode did not change.

The paper also reports four limits.

  • The runs do not agree. Three separate runs of the mathematics task on the same model gave gains of 29.45, 5.00, and 27.30 points. All three runs changed the same matrix. The best run changed 1,023 values. The weakest run changed more than one million values. Thus the size of an edit does not predict its effect.
  • The gains are smaller on unseen questions. The main table has 14 runs. In each of the 14, the gain on the test set is smaller than the best gain on the development data. Part of this difference is expected, because the development number is the best of many candidates.
  • The editor often kept the original weights. In 6 of the 16 runs, the editor could not validate a candidate edit, and it kept the original weights. On the 9B model, one mathematics candidate had a development gain of 29.69 points. On the test set, its score was 0.35 points lower than the base score.
  • A strong model has little to fix. Qwen3.5-9B has a base score of 97.70% on MATH-500. The edits that the editor kept gave it 1.85 points on IFEval, 3.03 on SciBench, and 1.54 on SciCode.
Scatter plot of 14 editing trajectories. The horizontal axis is the best gain seen on development data, from 0 to 48 points, and the vertical axis is the gain on held-out test data. A dashed diagonal marks where the two would be equal, and every point lies below it. The 0.8B IFEval and Math edits sit highest at about 37 and 29 held-out points from 44 development points. 0.8B SciBench is at 17 from 30. 0.8B SciCode is at 0 from 39. The 9B Math edit, shown as a hollow red square because it was discarded, is at minus 0.35 from 30. Most 9B points and all discarded edits cluster near zero held-out gain.
The 14 runs in the main table of the WSP-Scope paper. The horizontal axis shows the best gain on development data. The vertical axis shows the gain on unseen test questions. All 14 points are below the dashed line, so each test gain is smaller than the development gain. Hollow red markers show edits that the editor did not keep. The large gains are all on the 0.8B model. Data from Table 2 of Hu et al.

Two comparisons with the original post are useful. First, the original gain on MATH-500 was about 40 points. This is larger than the gain in each of the three WSP-Scope runs. The two groups measured slightly different base scores, 7.9% and 8.35%, so their evaluations are not identical. Second, the pattern agrees with the Gemma control. A weak model with one specific fault improves a lot. A model with no such fault improves little.

The original post mentions one more check. The authors say that Ahsen Khaliq at Hugging Face rebuilt the edited Qwen model from the published logs and ran the evaluation again. The post does not give his numbers. The edited weights are public, so other people can test the headline number.

Transformers written by hand

On 2 November, Chandan Singh published a report on a related test.9 He gave Claude, as a coding agent, an empty transformer and one rule: set each weight by hand, with no training. He describes the report as project notes that he wrote up quickly.

The report covers ten algorithmic tasks, which include addition, multiplication, parity, and a sort task. For each task, the agent got 100% accuracy on the 200 test examples in three attempts or fewer. Then it made its solutions smaller. Its parity network has 174 weights, and 35 of them are not zero. Each network comes with a description of what each part does, because the agent wrote the parts on purpose.

The report also lists problems with its own results.

  • All the tasks use one fixed set of test examples. The report says that each program needs a new evaluation on a different set.
  • On three language tasks, the agent could read the pool of sentences that contained the test examples. It started to fit statistics to that pool. On one task, it set its output weights with logistic regression on the test set and recorded 100%. The report says that this result is not valid.
  • On two tasks, the agent got to “zero parameters”. It moved its constants to a part of the model that the parameter count ignores.

The lesson from this report is about measurement. An agent that must maximise a number can find weak points in how the number is measured. This is why the unseen test sets in the original post and in WSP-Scope are important.

What the evidence shows

This section is my summary of the sources above.

Reported by two groups, with public logs or public code:

  • An LLM with Python and a small budget of forward passes can find and remove a specific fault in a small language model. The edit changes a very small fraction of the weights. The gain stays on test questions that the editor did not see.
  • An edit of this type can also help on other tasks, when the fault is a general one such as a loop.

Reported by one group, with public logs:

  • An LLM can write weights that work for small games and for 9×9 Go. This is from the original post.
  • An LLM agent can write small transformers for algorithmic tasks. This is from Singh’s report, which needs a new evaluation on new test examples.
  • An LLM can name the purpose of a very small network from its raw weights with no tools. This is from the original post. The one audit of a similar task used a different model and a harder setup, and it found many errors of meaning.

Tested, with a negative result:

  • An edit did not add an ability that a model did not have. The Gemma control and the 9B results both show this.
  • The editor could not read the behaviour of a released language model from its weights only. Experiment 7 failed until the editor could see attention patterns.

Not known at this time:

  • Reliability. Gains were very different between runs, and the editor kept the original weights in 6 of 16 WSP-Scope runs.
  • Scale. The largest target in these sources is Qwen3.5-9B, and its gains were a few points or less.
  • Cost. No source gives the time or the cost of an edit. Thus there is no evidence for a comparison with the cost of training or of a human researcher.

The original authors also list possible future uses. These include audits of a model without an evaluation run and changes to abilities without data. They also include merges of models with different architectures, and a model that improves its own weights. The sources in this post do not test these uses. The authors say that they are building a benchmark and a standard harness. This will help, because much of the present dispute is about access and about measurement.

In my view, the sentence from the Gemma control is the best short summary. The method can remove an obstacle that hides an ability. It is an open question whether the method can do more than that.

Try it yourself

Both toy examples in about 50 lines of numpy (click to expand)

The first part writes the 51-weight paddle network by hand and tests it on each of the 100 states. The second part removes one direction from 64 columns of a random matrix. The matrix has the shape that the WSP-Scope paper reports for an MLP output matrix in Qwen3.5-0.8B. You can change the number of columns, or select columns at random.

import numpy as np


def write_paddle_policy(width=10):
    """Hand-write a 51-weight network that moves a paddle under a ball."""
    cells = np.arange(width)
    # layer 1: two units that measure how far the ball is to the right / left
    W1 = np.zeros((2, 2 * width))
    W1[0, :width], W1[0, width:] = cells, -cells    # ball_x - paddle_x
    W1[1, :width], W1[1, width:] = -cells, cells    # paddle_x - ball_x
    b1 = np.zeros(2)
    # layer 2: logits for [left, stay, right]
    W2 = np.array([[0.0, 1.0], [0.0, 0.0], [1.0, 0.0]])
    b2 = np.array([0.0, 0.5, 0.0])
    return W1, b1, W2, b2


def policy_actions(weights, ball_x, paddle_x, width=10):
    """Run the network on one-hot ball and paddle positions."""
    W1, b1, W2, b2 = weights
    x = np.zeros((len(ball_x), 2 * width))
    x[np.arange(len(ball_x)), ball_x] = 1.0
    x[np.arange(len(ball_x)), width + paddle_x] = 1.0
    hidden = np.maximum(x @ W1.T + b1, 0.0)
    return (hidden @ W2.T + b2).argmax(axis=1) - 1   # -1 left, 0 stay, +1 right


def remove_direction(W, u, columns):
    """Delete direction u from what the chosen columns of W can write."""
    u = u / np.linalg.norm(u)
    W_new = W.copy()
    W_new[:, columns] -= np.outer(u, u @ W[:, columns])
    return W_new


# 1. the hand-written paddle policy, checked on every state
weights = write_paddle_policy()
ball, paddle = np.meshgrid(np.arange(10), np.arange(10), indexing="ij")
ball, paddle = ball.ravel(), paddle.ravel()
actions = policy_actions(weights, ball, paddle)
n_weights = sum(w.size for w in weights)
n_nonzero = sum(int(np.count_nonzero(w)) for w in weights)
print(f"paddle policy: {n_weights} weights, {n_nonzero} nonzero")
print(f"correct on {(actions == np.sign(ball - paddle)).sum()} of "
      f"{len(actions)} states")

# 2. removing one direction from 64 columns of a 1024 x 3584 matrix
rng = np.random.default_rng(0)
W = rng.normal(0.0, 0.02, size=(1024, 3584))
u = rng.normal(size=1024)
u /= np.linalg.norm(u)
columns = np.argsort(-np.abs(u @ W))[:64]     # the 64 strongest writers
W_new = remove_direction(W, u, columns)
changed = int((W_new != W).sum())
print(f"entries changed: {changed} of {W.size} "
      f"({100 * changed / W.size:.2f}% of this matrix)")
print(f"largest write along u, before: {np.abs(u @ W[:, columns]).max():.3f}")
print(f"largest write along u, after:  "
      f"{np.abs(u @ W_new[:, columns]).max():.1e}")
print(f"two such matrices: {2 * changed} entries = "
      f"{100 * 2 * changed / 0.8e9:.3f}% of 0.8 billion")

# paddle policy: 51 weights, 39 nonzero
# correct on 100 of 100 states
# entries changed: 65536 of 3670016 (1.79% of this matrix)
# largest write along u, before: 0.067
# largest write along u, after:  4.9e-17
# two such matrices: 131072 entries = 0.016% of 0.8 billion

Sources & further reading

Footnotes

  1. Tracr: Compiled Transformers as a Laboratory for Interpretability by Lindner and colleagues, 2023. ↩

  2. Locating and Editing Factual Associations in GPT by Meng, Bau, Andonian and Belinkov, 2022. ↩

  3. A Mathematical Framework for Transformer Circuits by Elhage and colleagues, 2021. Code repeats names more often than prose does. Thus the editor reasoned that a model with many copying heads was trained on code. ↩

  4. Refusal in Language Models Is Mediated by a Single Direction by Arditi and colleagues, 2024. Sean Goedecke’s critique compares the editor’s procedure to a tool that uses this approach. ↩

  5. The ‘Astra can read and write weights to improve Qwen’ post is misleading, Matthew Honnibal, 3 November 2026. He also gives his opinion that AI models from one or two years before would have failed at all these tasks. ↩

  6. LLMs are not superhuman at reading and writing neural network weights, Sean Goedecke, 3 November 2026. He also says that the result impresses him, but that it does not change his view of what these models can do. ↩

  7. Can an LLM Actually Reason and Program about Neural Network’s Weights or is it just memorization on steroids?, Nazmus Sakib Ahmed, arXiv, 5 November 2026. ↩

  8. Exploring Weight-Space Programming: Capabilities, Generalization, and Limitations, Hu, Tang, Li, Zhu, Feng, Zhang, Chen and Hu, arXiv, 6 November 2026. ↩

  9. Weight-Space Programming from scratch on simple tasks, Chandan Singh, 2 November 2026. ↩

Citation Information

If you find this content useful, please cite this work as:

Bhana, Nish. "Weight-Space Programming: Can an LLM Read and Write Another Network's Weights?". Nish Blog (November 2026). https://www.nishbhana.com/Weight-Space-Programming/

Or use the BibTeX citation:

@article{bhana2026weightspace,
  title   = {Weight-Space Programming: Can an LLM Read and Write Another Network's Weights?},
  author  = {Bhana, Nish},
  journal = {nishbhana.com},
  year    = {2026},
  month   = {November},
  url     = {https://www.nishbhana.com/Weight-Space-Programming/}
}

x.com, Facebook