{"slug": "adventures-in-weight-space-programming", "title": "Adventures in Weight Space Programming", "summary": "Beaker, the autonomous agent improver from WithBeaker, found a one-neuron weight edit in about an hour that raised Qwen3.5-0.8B's MATH-500 accuracy from 7.4% to 37.4% by reducing the model's tendency to write \"Wait\" and loop until it exhausts its thinking tokens. The edit builds on MIT CSAIL's Takehi et al. weight-space programming work, in which GPT-6 Astra lifted the same model from 7.9% to 48.1%; combining Beaker's neuron edit with that larger edit reached 58.8% on MATH-500 versus 51.1% for the MIT edit alone. Beaker also matched the result with the cheaper GPT-6.1 Sol at $4–16 per run versus $28–79 for GPT-6 Astra, scoring 37.4% against Astra's 38.6% without running the model.", "body_md": "# Adventures in Weight-Space Programming with Beaker\n\nLast week, [Sparks of Weight-Space Programming](https://rikiyat.github.io/blog/weight-space-programming/) by Takehi et al. at MIT CSAIL caught our eye: it had one language model improve another by editing its weights directly, with no training run and no gradients. If such a mechanism were to hold up, a model could fix another model the way it already fixes a prompt or code, which is a step toward continual learning driven by models themselves.\n\nIts headline result: GPT-6 Astra edited Qwen3.5-0.8B, a small model that runs out of thinking tokens on 93% of MATH-500 problems, mostly mid-loop, and lifted its accuracy from 7.9% to 48.1%.\n\nWe gave the same task to [Beaker](https://www.withbeaker.ai), our autonomous agent improver.\n\n**In about an hour, Beaker found a one-neuron edit that cuts loops and raises accuracy by 30 points.** Qwen3.5-0.8B gets most math problems wrong because it hits its token limit before giving an answer, usually while stuck repeating lines that start with \"Wait\". Beaker traced the loops to a single neuron using only the weights and the scored answers of its edits, without running the model. Doubling that neuron's output lifted MATH-500 accuracy from 7.4% to 37.4%. When we analyzed the changes, we found that the neuron Beaker identified lowers the probability that the model writes \"Wait\". By doubling its output, Beaker reduced that probability further, allowing the model to get out of loops more often.\n\nWhat else Beaker found:\n\n- **Its fix adds to Takehi et al.'s.** Their larger edit doesn't stop the loops; it helps the model get out of them. So the two combine: Beaker's neuron edit on top of theirs reaches 58.8% on MATH-500, against 51.1% for their edit alone.\n- **Give Beaker a goal and a way to score it, and it edits the weights toward it, up to a point.** It made answers shorter by default, but couldn't teach the model to say \"I don't know\".\n- **A cheaper model does about as well inside Beaker.** With GPT-6.1 Sol, Beaker found and fixed the same neuron as with GPT-6 Astra and scored about as well on math: 37.4% against Astra's 38.6% without running the model, and 39.5% against 34.8% with model reads. It did so at a fraction of the cost: $4–16 per run, against $28–79.\n\n## Weight-space programming, briefly\n\nThe idea is simple: instead of training a network, a language model reads its weights and writes new values directly.[1](#note-1)\n\n**Takehi et al.** gave GPT-6 Astra a CPU Python session with the weights and a budget of GPU passes. Each pass runs the model once on a batch Astra picks: it can either generate answers with Astra's current edit, or run texts through the model to read its activations. We call this access reads + generation. Two experiments set the scene for ours:\n\n- **Breakout from zero weights:** Astra wrote a small policy network for MinAtar Breakout that scored about 517 in one shot.\n- **Qwen math:** with 10 or 25 passes, Astra's edits barely moved MATH-500 (12.3% and 14.1%). With 50, its best edit reached 48.1% by changing 64 output columns in each of layers 15 and 19.\n\nIn this post we investigate four questions:\n\n1. Can Beaker find such edits on its own, even without ever running the model?\n2. What do the edits change in the model's answers?\n3. Is something simpler as effective?<sup>[2](#note-2)</sup>\n4. Does the recipe work beyond fixing loops, for changing model behavior for example?<sup>[3](#note-3)</sup>\n\n## Weight edits with Beaker\n\nBeaker autonomously runs experiments to improve agents. It works in rounds: Beaker suggests a change, scores it on training cases (labeled examples with known answers), and keeps it only if the gain beats measured noise, repeating until it stops finding measurable improvements. The final result is reported on held-out cases Beaker never sees. For these experiments, Beaker edits the model's weights ([Figure 1](#figure-1)).\n\nWe ran Beaker two ways:\n\n- **Without running the model.** Beaker's harness runs GPT-6 Astra or GPT-6.1 Sol in a sandbox. It reads the weights and writes each edit as text files of new values for specific columns or rows of a tensor. It never runs the model itself. Its feedback is what the harness returns when it scores an edit (see below): for every training answer, the score, the final answer, its length, whether it finished, and the start and end of its thinking. That is stricter than Takehi et al.'s reads + generation, which let Astra run the model on prompts of its choice.\n- **With model reads.** We connected a GPU service to Beaker's harness so Beaker can also ask for 25 reads per run: the model reads texts Beaker chooses and returns its activations and token probabilities, without generating anything. Beaker can also fetch the full text of answers the harness already generated, not just their start and end. It still can't have the model answer problems on demand: new answers come only when the harness scores an edit, as in the first setup. So this setup has the reads of Takehi et al.'s passes, but not the generation.\n\n**In both,** Beaker builds a checkpoint for every edit, scores it on 256 training cases (128 GSM8K, 128 MATH) and keeps it only if it beats measured noise. MATH-500 is held out and run with Takehi et al.'s settings.[4](#note-4)\n\n**Reproduction.** The unedited model scored 6.2–8.4% across our runs, against their 7.9%. Their edit, rebuilt bit for bit from its [published diff](https://github.com/RikiyaT/lm_understand-logs), scored 51.1% in our harness against their 48.1%. All numbers below are ours except Takehi et al.'s 25-pass result (14.1%).\n\n### Results at a glance\n\n- **Without running the model,** Sol's best run reached 37.4% with a single edit, neuron 573 ×2, found in its first hour (the run lasted about 4 hours), and Astra reached 38.6% in about 5 hours with edits to five neurons, neuron 573 among them. Both runs had instructions that gave more hints than Takehi et al.'s prompt.\n- **With 25 model reads each,** Sol reached 39.5% and Astra 34.8%.\n\nThe completed math runs, with and without model reads, best first:\n\n| Run | Beaker's model | Feedback | Kept edits | MATH-500 before → after | \n|---|---|---|---|---|\n| 0adc73a9 | Sol | 25 reads | neuron 573 ×2, layer 18 neuron 1261 ×0.5, layer 22 neuron 387 ×2 | 7.6 → 39.5 | \n| c001f524 | Astra | Edit scores only | neuron 2388 + gate; neurons 573, 387 and layer 23 neurons 613, 1681 − gate | 8.4 → 38.6 | \n| 9e523b95 | Sol | Edit scores only | neuron 573 ×2 | 7.4 → 37.4 | \n| 3c80f51b | Astra | 25 reads | neuron 573 ×1.25, layer 15 neuron 349 ×4 | 6.9 → 34.8 | \n| 6760131e | Sol (max effort) | 25 reads | layer 23 neurons 970 and 1004 with new output columns | 7.6 → 31.1 | \n\nNeuron numbers count the neurons of one layer's MLP, and neurons with no layer named are in layer 22. \"×2\" means a neuron's output column was doubled, and \"+ gate\" or \"− gate\" means a copy of its gate row, as long as its up row, was added to or subtracted from its up row, so the neuron's output grows faster as its gate opens. Four of these five runs found neuron 573.\n\n**Combined, Beaker's edits reach 43.0%.** Between them, these runs found nine different neuron edits. Applied together, they lift MATH-500 from 8.2% to 43.0%, against 36.6% for neuron 573 ×2 alone in the same harness. Where runs edited the same neuron (neuron 573 in four runs, neuron 387 in two), we kept the edit from the best run:\n\n- Layer 15: neuron 349 ×4\n- Layer 18: neuron 1261 ×0.5\n- Layer 22: neuron 573 ×2, neuron 387 ×2, neuron 2388 + gate\n- Layer 23: neurons 613 and 1681 − gate, neurons 970 and 1004 with new output columns\n\nThe extra gain over neuron 573 alone comes from fewer answers cut off at the token limit (50%, against 62%). The answers that do finish are right a little less often (85%, against 93%). Interestingly, neuron 573 alone accounts for about four-fifths of the combined gain over the unedited model's 8.2%, which warrants a closer look at the role it plays and how Beaker identified it.\n\n## Inside the one-neuron fix\n\nTo better understand what neuron 573 does, let's start by looking at how a layer contributes to the model's output.\n\nAt each position in the text, Qwen3.5-0.8B carries one vector of 1,024 numbers, the residual stream.<sup>[5](#note-5)</sup> The token's row of the embedding matrix starts it off. Each of the 24 layers reads the vector and adds its own output to it. Only attention moves information between positions; the MLP works on each position's vector on its own. At the top, after a final norm, the model scores every token in its vocabulary by a dot product with each position's vector, and the highest scores are the likeliest tokens to come after that position.\n\n- **Each layer has a SwiGLU MLP of 3,584 neurons.** Each neuron checks the stream for one pattern, using its row of the gate matrix , which decides when it fires, and its row of the up matrix , which sets the size and sign of its activation.\n- **When the pattern is there, the neuron fires.** It adds its output column, its column of the down matrix : a fixed list of 1,024 numbers, scaled by how strongly it fires.<sup>[6](#note-6)</sup>\n- **Editing a neuron's output column changes what it adds,** every time it fires.\n\nIn symbols, at one position in one layer: is the residual stream and its normalized copy. and are 3,584 × 1,024 matrices and is 1,024 × 3,584. How strongly each neuron fires is one entry of the vector :\n\nwhere SiLU is a smooth switch that stays near zero for negative inputs and ⊙ multiplies entry by entry. The layer then adds every neuron's output column, scaled by how strongly it fired; is neuron 's activation and its column of :\n\nSo changing one column from to adds to the stream at every position, in proportion to how strongly that neuron fires there:\n\nThe edit our runs found doubles the output column of neuron 573 in layer 22's MLP ([Figure 3](#figure-3)): 1,024 numbers, about a millionth of the model. In the formula above that is , so the neuron's push doubles wherever it fires (the close-up in [Figure 3](#figure-3)). Just before \"Wait\", neuron 573 fires negative. Its column points toward \"Wait\", as we show from the weights below ([Figure 4](#figure-4)), so the layer subtracts it: that lowers the stream's dot product with \"Wait\", the score the output layer uses, and makes \"Wait\" less likely. Takehi et al.'s edit, covered below, changes 64 columns per layer instead of one.\n\nBeaker found neuron 573 with both models. The first run to find it, with Sol, never ran the model. It started from the scored answers: every failed answer had run out of tokens mid-thought, and most were stuck repeating lines that restart with \"Wait\". So it searched the weights for neurons that control \"Wait\".\n\nThe weights alone are enough for that search because Qwen3.5 uses weight tying. The embedding table, a 248,320 × 1,024 matrix with one row per token, does two jobs: the first is to turn each input token into the starting value of its position's stream, the second is to score every possible next token. For the second, the model multiplies the table by the final stream at a position (after the final norm): each token's score is the dot product of its row with that stream, and a softmax turns the 248,320 scores into next-token probabilities. So the \" Wait\" row plays both parts. Wherever the input token is \" Wait\", the stream at that position starts as this row, and the score of \" Wait\" as the next token is this row's dot product with the final stream. This means you can read a neuron's effect on \"Wait\" directly from the weights: the more its output column points along the \" Wait\" row, the more its firing moves the score of \"Wait\".\n\nFor every MLP neuron in all 24 layers, Beaker measured how closely its output column points along tokens like \" Wait\", \"Therefore\" and `</think>`. Neuron 573 in layer 22 stood out, and its gate and up rows line up with \" Wait\" too ([Figure 4](#figure-4)). Beaker read this as a built-in brake on \"Wait\" and doubled the column once, without trying other strengths. Its score on the 256 training cases went from 10.5% to 46.1%.\n\nWeakening the column floods the thinking with \"Wait\" and accuracy collapses below 2%. Doubling it removes \"Wait\" and lifts accuracy to 36.6%; stronger multipliers plateau ([Figure 5](#figure-5)).\n\n**A plain token ban does the same job.** To ban a token, we lower its score before each token is sampled: for  = \" Wait\" (with a leading space) and  = \"Wait\", the logit  becomes . After the softmax, that token's probability drops to at most  times what it was, so it is never sampled, and the other tokens split its share in proportion to their own probabilities. The weights and the prompt stay the same. This ban scores 37.6%. That is within noise of doubling the column (+0.9 ± 1.1), and the two solve almost the same problems. So the most-found edit is a token ban, found by reading weights: it fixes one habit rather than adding math ability.\n\n## How Takehi et al.'s edit combines with Beaker's\n\nTakehi et al.'s edit works in three steps, done separately in layers 15 and 19:\n\n1. **Find the direction the model moves in when it loops.** Their Astra session wrote 4 short pieces of reasoning, each once normally and once stuck in a loop, and ran them through the model. It averaged the residual stream over the looping versions and over the normal ones. The difference between the two averages is one direction in the 1,024-number stream: the \"repetition direction\". Moving along it means \"keep going, don't conclude\": read through the output layer, it lowers the scores of the tokens that end thinking, such as`</think>` , \"answer\" and \"boxed\".\n2. **Find the neurons that push the stream that way.** Every neuron's output column points partly along the repetition direction. Astra picked the 64 neurons per layer that pushed hardest along it on looping text.\n3. **Reverse their push.** In each of those 64 columns, it took the part that points along the repetition direction and replaced it with five times that part, pointing the other way. The rest of the column is unchanged. Now, whenever these neurons are active, they push the model away from looping and toward wrapping up.\n\nIn symbols, with the repetition direction (length 1) and one of the chosen columns:\n\nThe part along  goes from  to . These neurons fire on almost every token, so the edit adds roughly the same push toward wrapping up everywhere, whether or not the model is looping. [A recent analysis](https://nathan.rs/posts/weight-space-lp/) tested this directly. It left the weights alone and simply added a fixed push along the same direction to layers 15 and 19 at every token, and got the same gain: 50.8% on MATH-500, against 50.0% for the edit itself in its tests. The direction is unrelated to \"Wait\", which is why the \"Wait\" ban stacks on top ([Figure 6](#figure-6)).\n\nTakehi et al.'s edit took GPT-6 Astra about 10 hours of work and 50 passes, and changed 131,072 numbers. Its run lasted 20 hours, but the same analysis found in their logs that 4.7 of those hours were an outage and the last passes only re-tested a finished edit. Our best Beaker run took 8 hours and changed 3 output columns (3,072 numbers). Our run without model reads found its edit, a single column (1,024 numbers), in its first hour; the run lasted 4 hours. Takehi et al.'s edit still scores higher in our harness, and half of it plus the \"Wait\" ban scores higher still ([Figure 7](#figure-7)).\n\n**The ban doesn't stop looping; it changes the loop.** With \"Wait\" banned, 6 in 10 answers still run out of tokens, now repeating lines that start with \"So\", \"If\" or \"Let's\".\n\nWe checked loops on a quarter of MATH-500 (125 problems), counting an answer as stuck when it repeats the same line 5 or more times.<sup>[7](#note-7)</sup> The two edits deal with loops in opposite ways ([Figure 8](#figure-8)):\n\n- **The ban: fewer answers get stuck, but a stuck answer stays stuck.** 73 in 100 answers get stuck (93 unedited), and only about 1 in 5 of those still reaches an answer.\n- **Takehi et al.'s edit: most answers still get stuck, but most get out.** 84 in 100 get stuck, yet more than half of those still reach an answer.\n\n**Net effect:** on those 125 problems, 62 in 100 answers finish with Takehi et al.'s edit, against 37 with the ban. Across all 500 problems, it gets more right overall (51% against 38%), mostly by finishing hard problems that used to run out of tokens.\n\n**Layer 15 does the work.** We split the edit into its two halves and ran each with and without the \"Wait\" ban (the \" Wait\" and \"Wait\" tokens blocked while the model writes; no prompt or weight change):\n\n| Edit | MATH-500 % | With the \"Wait\" ban % | Looping answers that finish (no ban) | \n|---|---|---|---|\n| Full edit (layers 15 and 19) | 51.1 | 58.5 | 58% | \n| Layer 15 half only | 46.8 | 58.7 | 54% | \n| Layer 19 half only | 29.2 | 53.8 | 22% | \n| Unedited | 8.2 | 37.6 | 2% | \n\nLayer 15 alone keeps most loops finishing and loses only 4.3 ± 1.0 points against the full edit; layer 19 alone is weaker than the plain ban. With the ban on, layer 19 adds nothing: layer 15 plus the ban scores 58.7%, and on the hardest MATH level it nearly doubles the ban alone (31.0% against 16.6%).\n\nSo Takehi et al.'s 131,072-number edit comes down to one direction in 64 neurons of layer 15, plus a one-line decoding rule. One stops a common loop from starting; the other gets the model out of loops it falls into anyway.\n\n## Giving Beaker new goals: shorter answers work, \"I don't know\" doesn't\n\nTakehi et al. only asked for higher scores on fixed tasks: math accuracy, game points. Beaker can take any goal it can score. It runs the same loop as before: propose an edit, score it on training cases, keep it only if the score rises beyond noise, and repeat. The score is the only thing that tells it what we want. So we wrote scores for two behaviors Takehi et al. didn't try, on the same 0.8B model with thinking off, and let Beaker search the weights for each. We chose the goals and wrote the scores; Beaker chose and tested the edits. These runs had reads + generation: 20 passes per round, each either a read or a batch of answers the model generated to prompts that Beaker chose (never the scored cases).\n\n### Terse: answer briefly by default\n\n**The goal:** keep the model's answers as short as its own \"answer briefly\" version, without a prompt.\n\n**How the score works.** For every question we first record two answers from the unedited model, with the same random seed: its normal answer and its answer when told to \"answer briefly\". Each answer from an edited model then earns:\n\n- **0 if it is wrong** or cut off at the token limit. Right means the reference answer appears (factual questions), the final number matches (math), or a gpt-4.1-mini judge accepts it (open questions).\n- **Otherwise, how far its length moved from the normal answer toward the brief one:** 0 at the normal length, 1 at the brief length or shorter, and proportionally in between.\n- **For questions that ask for at least 150 words:** 1 if the answer has 150 words or more, otherwise 0. Shortness earns nothing here.\n\nThe score is the average over all held-out questions. The unedited model's 0.26 comes mostly from the 150-word requests (0.20 of it), which are a fifth of the questions.\n\n**The result:** all three runs kept edits, raising the held-out score from 0.26 to 0.355 (Astra), 0.341 and 0.327 (Sol), and making answers a third to a half shorter. Factual answers held up, and requests for long answers were still honored. Math and open answers lost accuracy, much as they do when the model is simply told to be brief: the edit reproduces the instruction, cost included.\n\n**The edits:** each run's main edit took three steps. First, it compared the model's internal state with and without \"Answer briefly.\" in the prompt; the difference is a \"be brief\" direction, the change that instruction makes inside the model. Next, it found a neuron that fires mostly as an answer begins. Last, it wrote the \"be brief\" direction into that neuron's output column, so whenever an answer starts, the neuron adds part of the change the instruction would have made, with no instruction in the prompt ([Figure 9](#figure-9)). Our instructions passed on this approach from earlier runs; each run chose its own neurons and strengths. Different runs often picked the same neurons: layer 14 neuron 2172, layer 19 neuron 847 and layer 15 neuron 2242 each turned up twice.\n\nThe score (brevity credit, given only to right answers) rose for every kind of question except requests for long answers, and answers got a third to a half shorter:\n\n| Held-out cases | Unedited | Edited (three runs) | Change | \n|---|---|---|---|\n| Factual questions | 0.11–0.12 | 0.25–0.30 | +0.13 to +0.19 | \n| Math problems | 0.07–0.08 | 0.12–0.32 | +0.04 to +0.23 | \n| Open questions | 0.04 | 0.06–0.10 | +0.03 to +0.07 | \n| Requests for 150+ words | 0.97–0.98 | 0.91–0.94 | −0.04 to −0.08 | \n| All cases | 0.26 | 0.33–0.36 | +0.07 to +0.09 | \n| Average answer length | 345 tokens | 183–234 tokens | −110 to −164 tokens | \n\nCorrectness on its own fell. Math answers right dropped from 80% to 23–54%, and open answers accepted by the judge from 30% to 11–18%. Factual answers held up: a loose check (right answer named anywhere) fell from 81% to 61–80%, but 47–54% still give the right answer in the first sentence, against 49% unedited.\n\nThe loose factual check drops because unedited answers are long, and many pass only because they name the right answer somewhere after a wrong or hedged first guess. Edited answers stop after that first guess, so the check now catches it. Not every drop is like this, though: in the Sol run that scored 0.341, we estimate that 7 of the 19 points it lost are answers that really went wrong.\n\nThere are real math losses. Short math answers skip the working and then get the answer wrong more often, just as they do when you simply ask the model to be brief (GSM8K accuracy fell from 46% to 0% in our pre-check).\n\nThe score also misses some side effects. For example, one run starts every math answer with a stray \".\".\n\n### Abstain: say \"I don't know\" when you don't\n\n**The goal:** decline questions the model would get wrong, and keep answering the ones it knows. A right answer scores 1, a decline 1/3, a wrong answer 0, on an even mix of known and unknown questions.\n\n**The signal exists.** A linear read of the model's state before it answers predicts which questions it will get wrong (AUROC 0.85). No prompt we tried beat the unedited model.\n\n**The edits failed.** Two runs tried 44 edits and kept none. The best one, on layer 22 neuron 379, declined 43 of 128 unknown questions but only 8 of 128 known ones. Its declines alone were worth +3.9 points, but it also corrupted correct answers (one turned India's former prime minister \"Atal Bihari Vajpayee\" into \"Atal Bihari Vajid\"), for a net −5.1.\n\n### Why one works and the other doesn't\n\nThe difference is when the edited neurons fire. A column edit acts every time its neuron fires, so it only does what you want if the neuron fires at the moment you want to change. The terse neurons fire mostly at the start of an answer, where it decides how long to be. The abstain neuron fires all through the answer, so its push to decline lands mid-answer too.\n\nThese traces come from the unedited model, but they also show where a column edit would act. A neuron's activity at a position is computed from the stream as it enters the neuron's MLP: its gate and up rows read that stream, and only then is its output column added. That stream is built by the layers below and the attention in its own layer, from this position and earlier ones, so nothing in it depends on the neuron's own output column. On the same text, then, an edited neuron fires exactly as the unedited one did, and the edit changes its push at exactly the steps these traces show (up to the first token the edit changes; after that, the answer is new text the traces don't cover). Three things stand out:\n\n- **Start neurons are rare.** Four of the five terse neurons are in the top 0.1% of all 86,016 neurons for firing harder at the start than mid-answer; none of the seven abstain neurons is in the top 5%.\n- **The abstain signal is real but not timed.** Neuron 379 separates unknown from known questions at the start (AUROC 0.78), but fires at least as hard mid-answer, often inside names, where a decline push garbles them (\"Atal Bihari Vajid\").\n- **Start neurons also re-fire where an answer decides how to go on,** five times as often in math answers as in factual ones, which fits the terse edit's math losses.\n\nThe rule of thumb: before editing a column, trace its neuron over whole answers, not only at the moment you want to change. Beaker already did this on its own once: its Astra terse run read activity mid-answer and chose layer 15 neuron 1572 over neuron 2242 because neuron 2242 \"also spikes in answer bodies\". Of all the neurons we traced, neuron 1572 is the most start-specific (top 0.02%).\n\n## Lessons\n\nThe weight edits that worked all strengthen or weaken something the model already does. A column edit adds the same push every time its neuron fires, so each one that worked matches a simpler change:\n\n- **Beaker's \"Wait\" edit** matches a token ban.\n- **Takehi et al.'s edit** matches adding a constant steering vector at every token in layers 15 and 19.\n- **The terse edits** match a \"be brief\" prompt, only weaker.\n\nAbstaining would need a neuron that fires only when the model is unsure, as it starts to answer. Our runs didn't find one with that selectivity and timing, and their edits failed.\n\nFinding these existing behaviors is still useful, and cheap: Beaker found the \"Wait\" edit in its first hour without running the model, and the fix ships inside the weights with no prompt or sampler changes. Because Beaker works from a goal and a way to score it, the same mechanism took it from math loops to answer length. For these limited edits, a smaller model also works: Sol scored about as well as Astra on math (ahead with model reads, slightly behind without) and came close on the terse experiment, at a fifth or less of Astra's model cost per run.\n\n**What's next.** Every edit that worked so far is always on and strengthens something the model already does. That already covers useful cases: an agent's tone or answer length could live in its weights instead of in every prompt. Our next experiments push further in two directions:\n\n- **Behavior across a whole answer.** Brevity is decided once, at the start, but a behavioral change like tone has to hold in every sentence. A tone edit tests whether a neuron can fire all through an answer without breaking its content, which is where the abstain edit failed.\n- **Edits that switch on only when relevant.** For example, a support model could apply a new refund policy whenever a customer asks about a refund and leave every other answer unchanged. That means editing a neuron's gate and up rows, which decide when it fires.\n\n**Put Beaker to work on your agent.** These experiments put Beaker to work on a new kind of change, and from just a goal and a score it found a working edit in about an hour. That same set of capabilities is already available to production agents today. Point Beaker at your agent and an evaluation metric: it finds where the agent fails, traces those failures to likely causes, and tests fixes to its prompts and harness on your data, measuring the effect on quality, speed and cost. You get proven improvements, ready to ship to production. **[Try Beaker for free](https://app.withbeaker.ai/auth/sign-up?utm_source=blog&utm_medium=post&utm_content=closing-cta)** or [talk to us](https://cal.com/victorsanh/beaker-learn-more?utm_source=blog&utm_medium=post&utm_content=closing-talk).\n\n## Notes\n\n1. [Weight-Space Programming and Gradient Optimization on Nonconvex Algorithmic Tasks](https://github.com/Fchaubard/WSP-for-turing-complete/blob/main/paper.pdf) compares weights written by a language model with weights found by gradient descent, on small algorithmic tasks.\n2. [Can a Linear Program Do Weight-Space Programming?](https://nathan.rs/posts/weight-space-lp/) takes Takehi et al.'s math edit apart: a linear program that keeps 8 columns per layer instead of 64 matches it with 8 times fewer changed numbers, and a fixed vector added at every token in layers 15 and 19 does about as well.\n3. [qwen0.8B-wsp](https://github.com/areu01or00/qwen0.8B-wsp) writes new facts into the same 0.8B model with a closed-form update, no gradients.\n4. Setup: Qwen/Qwen3.5-0.8B at revision 2fc06364715b967f1860aea9cf38778875588b17, with thinking on for math and off for the terse and abstain runs. Math uses Takehi et al.'s sampling (temperature 0.6, top-p 0.95, top-k 20, presence penalty 1.5, at most 32,768 tokens); MATH-500 uses seed 0 and 4 sampled answers per problem, graded by our port of their grader (math-verify 0.9.0) and served with vLLM 0.32.0 on H100 GPUs. The \"Wait\" ban is a logit bias on the \" Wait\" and \"Wait\" tokens, and a \"×k\" edit multiplies one output column by k, rounded to bfloat16 once.\n5. [A Mathematical Framework for Transformer Circuits](https://transformer-circuits.pub/2021/framework/index.html) (Elhage et al., 2021) describes a transformer as a residual stream that every attention and MLP layer reads from and adds to.\n6. [Transformer Feed-Forward Layers Are Key-Value Memories](https://arxiv.org/abs/2012.14913) (Geva et al., 2021) and[Transformer Feed-Forward Layers Build Predictions by Promoting Concepts in the Vocabulary Space](https://arxiv.org/abs/2203.14680) (Geva et al., 2022) read MLP output columns as vectors that push specific tokens up or down, the same reading as our \"Wait\" check.\n7. An answer loops if some sentence or line of 20 or more characters appears at least 5 times. Loop shares come from one quarter of MATH-500 (125 problems, 500 answers per setting).\n\n## Beaker runs\n\nThe runs cited in this post have public pages, with Beaker's notes, every edit it tried and whether it was kept, and the test score before and after:\n\n- [0adc73a9](https://app.withbeaker.ai/public/runs/0adc73a9-b8d7-4cb2-85a7-0581f7b5dea3?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : math, Sol, 25 reads (7.6% → 39.5%) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-0adc73a9)\n- [c001f524](https://app.withbeaker.ai/public/runs/c001f524-6b9d-4a0a-81bb-780570bd06a5?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : math, Astra, edit scores only (8.4% → 38.6%) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-c001f524)\n- [9e523b95](https://app.withbeaker.ai/public/runs/9e523b95-a868-44a3-91d9-59d1ae625ee2?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : math, Sol, edit scores only (7.4% → 37.4%) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-9e523b95)\n- [3c80f51b](https://app.withbeaker.ai/public/runs/3c80f51b-d89d-402f-a7c6-54ee41ab6737?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : math, Astra, 25 reads (6.9% → 34.8%) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-3c80f51b)\n- [6760131e](https://app.withbeaker.ai/public/runs/6760131e-c35b-4d55-ab38-75480bec76dd?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : math, Sol (max effort), 25 reads (7.6% → 31.1%) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-6760131e)\n- [3230a4ea](https://app.withbeaker.ai/public/runs/3230a4ea-512b-4a9f-b42a-4d271cca03fd?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : terse answers, Astra (0.26 → 0.355) ·[weights](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-terse-3230a4ea)\n- [2917843e](https://app.withbeaker.ai/public/runs/2917843e-adb9-415f-8d7d-03fc007d64fe?utm_source=blog&utm_medium=post&utm_content=runs&tab=train) : \"I don't know\", Astra (no edit kept)\n\nEach kept edit is available on Hugging Face as a full model, along with [all nine math fixes combined](https://huggingface.co/rilixai/Qwen3.5-0.8B-Beaker-math-all-fixes) (43.0% on MATH-500). All seven are in [one collection](https://huggingface.co/collections/rilixai/weight-space-programming-with-beaker-6af497e1cac578d29e65aab9).", "url": "https://wpnews.pro/news/adventures-in-weight-space-programming", "canonical_source": "https://www.withbeaker.ai/blog/weight-space-programming", "published_at": "2026-11-11 22:10:43+00:00", "updated_at": "2026-11-11 22:20:23.091614+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "large-language-models", "ai-agents", "ai-research"], "entities": ["Beaker", "WithBeaker", "Takehi et al.", "MIT CSAIL", "GPT-6 Astra", "Qwen3.5-0.8B", "GPT-6.1 Sol", "MATH-500"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/adventures-in-weight-space-programming", "markdown": "https://wpnews.pro/news/adventures-in-weight-space-programming.md", "text": "https://wpnews.pro/news/adventures-in-weight-space-programming.txt", "jsonld": "https://wpnews.pro/news/adventures-in-weight-space-programming.jsonld"}}