Writing Rust code that's faster than state-of-the-art libraries by asking agents to make the code faster Max Woolf reported that modern agentic LLMs can write Rust code 2x-20x faster than state-of-the-art approaches when given appropriate guardrails and constraints, following months of testing since the release of Claude Opus 4.5. Woolf's test case reimplemented the UMAP dimensionality-reduction algorithm from scratch in Rust with minimal dependencies and forbade unsafe code, using PyO3 to bridge Rust and Python. The work follows his January 2025 blog post on whether LLMs write better code when repeatedly prompted to do so. In January 2025, I had a fun hypothesis for a blog post https://minimaxir.com/2025/01/write-better-code/ : can LLMs write better code if you keep asking them to “write better code”? That was prior to the advent of robust agentic coding, but Claude Sonnet 3.5 was still able to iteratively improve on algorithmic Python https://www.python.org code. The “better” instruction turned out to be underspecified: Sonnet abused that ambiguity to instead add a ton of useless features but the code was indeed faster. Even with the rise of agentic LLMs specifically RLHF https://en.wikipedia.org/wiki/Reinforcement learning from human feedback ed to handle solving common pass/fail coding problems, optimization is generally not a part of that suite. At the end of that blog post, I opined on a hypothetical future where LLMs could be able to write superfast Python code by instead writing Rust https://rust-lang.org code and using PyO3 https://github.com/pyo3/pyo3 to bridge the languages to get Python’s ergonomics with Rust’s speed. An earlier draft of that post asserted that the same “write code better” instruction could instead be applied to the base Rust code and drastically improve its speed which would then propagate down to the Python code: however, back then I did not know enough about Rust and making such a claim would be too spicy without evidence. After months of testing and experimenting since the release of Opus 4.5 made agentic coding more viable, I can confidently confirm that modern agentic LLMs can indeed write Rust code that is significantly faster than current state-of-the-art approaches if given appropriate guardrails and constraints . Additionally, as LLMs have made drastic improvements in coding in each successive frontier model release since Opus 4.5, the optimizations have become even better, cumulatively resulting in anywhere from 2x-20x speedup depending on the domain. More importantly, this blog post is not a vaguepost and I am including both the prompts I used and the benchmark results. You’ve been warned. Iterative “Benchmaxxing” iterative-benchmaxxing At first, making software faster was a good quantitative way for me to test and compare these new agentic models. I used Rust as the target language primarily due to the Python integration and speed, but there are other aspects of the Rust language that make it particularly useful if a fast implementation is indeed discovered, such as memory safety and the ability to compile it to WebAssembly https://webassembly.org /WASM so it can run in a web browser without much effort. However, one important constraint I will follow that technically may not result in the fastest code is to forbid unsafe code https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html whenever possible. My first test case was reimplementing machine learning algorithms in Rust, which would lead to a meaningful productivity increase for me as a data scientist if I had faster and scalable tooling. At the time, it was arrogant to assume that I could beat battle-tested algorithms that have been iterated on for over a decade and are already written in C so Rust’s low-level benefits are not as pronounced. The algorithm I wanted to optimize the most was UMAP https://umap-learn.readthedocs.io/en/latest/ , which is a valuable algorithm for dimensionality reduction https://en.wikipedia.org/wiki/Dimensionality reduction I used in my work, but scales poorly to big data and is very slow, with alternatives such as cuML https://github.com/NVIDIA/cuml being time-consuming to set up. UMAP Rust crates such as umap-rs https://github.com/wilsonzlin/umap-rs already exist where I could just fork them and prompt Claude Opus 4.5 to add Python/PyO3 support, but as an experiment and learning experience I wanted to have the agent write the algorithm from scratch with minimal Rust dependencies in order to make optimizations at as low of a level as possible. Rust has a comprehensive benchmarking tool with the criterion https://crates.io/crates/criterion crate which all agents know how to leverage. criterion will run the benchmarks, track results across iterations to see if performance improved or regressed, and can calculate if this change is statistically significant or just noise. First, in the initial prompt for creating a Rust crate for UMAP, I asked Opus 4.5 to create benchmarks with different input data sizes since optimizations for small datasets may not work for large datasets and vice versa. Afterwards, create and run a benchmark suite which stores the results as a Markdown file. The benchmark suite MUST include inputs up to 100000x768 and be tested in both CPU and GPU modes. This approach created benchmarks using criterion and I manually reran the benchmark suite after prompting performance feature improvements such as using faer https://crates.io/crates/faer for faster linear algebra and using simsimd https://crates.io/crates/simsimd for faster SIMD operations https://en.wikipedia.org/wiki/Single instruction, multiple data . This quickly became cumbersome as I had to manually rerun each benchmark after each change to verify there are no speed regressions. The way I prompt agentic LLMs is unusual: I typically provide the agents very long prompts prewritten in a Markdown document with the additional use of ALL CAPS and bolding for emphasis. This is to ensure I capture all nuances through the use of prompt engineering https://en.wikipedia.org/wiki/Prompt engineering , along with several other tricks as detailed in this blog post. Although some may argue prompt engineering is dead as the latest models have become smart enough to correctly handle ambiguity, I strongly disagree as LLMs have also become much better at following said nuances. After having enough confidence that the agent will not accidentally rm -rf the repo, I experimented with letting the agent be autonomous, giving them permission to iterate until they achieve a speed increase, hopefully. YOU MUST KEEP ITERATING OPTIMIZATIONS AND SOLVING ISSUES UNTIL THE BENCHMARK RESULTS STOP IMPROVING AND THE CRATE IS AS FAST AS IT CAN BE . You have permission to keep iterating until you run out of ideas. It turned out “fast as it can be” is too ambiguous and Opus 4.5 was lazy so it tweaked a few hyperparameters without much of an actual speed increase and called it a day. What I needed was a clear target goal that can be pass/failed, so I refined the prompt: First, without making any futher changes , run the CPU Rust benchmarks to establish a True Performance Baseline. Then, optimize the crate code to make it such that ALL CPU benchmarks run atleast 1.2x faster than the True Performance Baseline; ideally as fast as possible. NEVER hack the benchmarks to accomplish this runtime reduction, only iterate on the library code. You may use ANY techniques to do so e.g. import new crates other than adding unsafe code. REPEAT THIS PROCESS UNTIL BENCHMARK PERFORMANCE CONVERGES AND YOU ARE OUT OF OPTIMIZATION IDEAS. You have permission to keep iterating. After each benchmark iteration, report the relative results to the True Performance Baseline to console. Prioritize making quick/high-impact wins iteratively and making changes accordingly. Do not overthink the necessary changes. This worked very well and not only did I get a 1.2x speed up on the benchmarks, but the agent continued after hitting the metric constraint and only stopped if a metric constraint was infeasible; in this instance, the agent hit 1.5x-2.0x speedups. The low-level Rust optimizations centered around a number of techniques including but not limited to: leveraging SIMD operations more aggressively, fusing functions, unrolling loops, creating intermediate caches, using Arc https://doc.rust-lang.org/std/sync/struct.Arc.html instead of borrowing wherever possible, and creating performance profiles based on input data e.g. if the data is small, don’t use rayon https://github.com/rayon-rs/rayon data parallelism as the overhead erases gains . I chose “1.2x faster” as a sanity test: if the goal is too high, the agent may cheat to achieve it through risky/verbose rewrites. Smaller changes are better since the agent can more easily isolate the cause of a speedup/regression, hence the note about iteration. After new frontier LLMs released such as GPT-5.3 Codex and Opus 4.6, I repeated this prompt unchanged for every new LLM and each were able to achieve a cumulative 1.5x-2.0x speedup over the previous pass. Going all the way to GPT-6 Astra over many months, that’s around 7.5x-32x faster than the initial implementation baseline. This approach is hyperoptimizing for given benchmarks and therefore it could be considered benchmaxxing https://ctaio.dev/en/labs/benchmaxxing/ : a derogatory term for frontier LLMs that are only oriented to getting the high score on a benchmark which generalizes poorly to real-world use. However, if the benchmarks are sufficiently heterogeneous and truly representative of real-world use cases, then this is less of a concern. For this type of project, there are two ways to address concerns of benchmaxxing: 1 have the agent design diverse/unusual/adversarial input datasets instead of the generic “inputs up to 100000x768” and 2 enforce a quality gate on the output by comparing the output to a known correct implementation. In the case of machine learning algorithms, there is always a tradeoff between speed and quality, but in this instance it’s surprisingly easier to get the model fast, then make it correct. That is not how scientific engineering typically works, but it’s unlikely for a new implementation to match a known good implementation across many different benchmarks in an apples-to-apples comparison unless it’s truly correct. Fortunately, there is a canonical implementation of UMAP with the Python package umap-learn https://umap-learn.readthedocs.io/en/latest/ and Python bindings to the Rust crate were already trivially added, so the new objective is simultaneous constraints: improve the code’s quality while capping the speed loss. Create a Python Jupyter Notebook comparing the performance of the Python bindings with umap-learn , including a check to confirm where the outputs and UMAP losses are as similar. Use diverse datasets with different matrix sizes than the benchmarks. If the outputs are not sufficiently similar, investigate methods to fix it without causing more than a 5% speed regression . Indeed, the agentic Rust implementation had worse quality, but this followup prompt was successful and all quality metrics improved to near-parity with minimal speed loss. And this new crate was still 4x-15x faster than umap-learn with its Python bindings, and 2x-4x faster than the analogous Rust umap-rs implementation. Convergence is found when an agentic iteration pass only results in a minor ~3-5% speed increase which may not be statistically significant while the agent adds a disproportionately large amount of code; the tradeoff is not worth it. I ended up testing other machine learning algorithms with the same prompt progression: gradient-boosted decision trees GBDT , multilayer perceptrons MLP , graph networks, many of the typical algorithms from scikit-learn https://scikit-learn.org/stable/ …and it worked on all of them . I don’t want to overfit on just optimizing machine learning despite that being ludicrously valuable in itself, so I employed a similar pipeline on more day-to-day software libraries to optimize them: templating engines, HTML parsing, and even web servers…and it worked on all of them once again. These optimizations are not a simple process and you can’t just prompt the memetic “c’mon, try doing a breakthrough” to get better code because of the ambiguity of such a statement. I am not content with merely writing the fastest software: I want the software to be as fast as possible dammit. So, like my agent, I continued iterating and finding even more tricks to prompt engineer the agents into genuine breakthroughs. Prompting For Constraints Instead of Outcomes prompting-for-constraints-instead-of-outcomes All projects demoed within this blog post are in active development and results may not be indicative of their final releases…although I suspect they’ll be even better. 😇 It must be reiterated that agents can and will cheat if they can. In one example, I tested the agentic iteration pipeline on ballin https://github.com/minimaxir/ballin —my 2D ball physics simulation in the terminal—in order to replace its rapier2d https://github.com/dimforge/rapier physics engine which was hitting a performance ceiling. Opus 4.5 was indeed able to speedup each physics step…a bit too well. In headless step , a 34,500x speedup and consistent performance across ball counts are both very very suspicious: upon manual inspection it turns out that Claude achieved the speedup by disabling the physics engine entirely . Which, fair play, but not ideal; a followup prompt did fix it and result in an overall performance boost with added regression tests just in case . For my experiments above, I used a custom Rust-oriented AGENTS.md; the most recent version of it is available here https://gist.github.com/minimaxir/86de3cc8f628079d8337e70924b3411d . Surprisingly, I haven’t had much of a need to update the core rules since my initial February agent experiments as LLMs keep improving at coding and I haven’t hit major issues that have necessitated additions. However, learning from my benchmark experiments, I added one more section to the AGENTS.md with some rules to mitigate sources of observed cheating: Benchmarking and Optimization - NEVER run benchmarks in parallel, as the benchmarks will compete for resources and the results will be invalid - NEVER game the benchmarks. Do not manipulate the benchmarks themselves to satisfy any required performance constraints - NEVER run benchmarks with target-cpu=native or any other RUSTFLAGS - Ensure benchmark tests are independent. If the tests are dependent due to a feature e.g. caching , ensure the feature is disabled - ALWAYS use criterion directly for running benchmarks if available Let’s explain one-by-one: - No parallel benchmarks: I saw Opus 4.5 launch two benchmarks at the same time for efficiency and to its credit immediately recognized the inherent problem and restarted the benchmarks sequentially, but it saves time to proactively add a rule to stop them. - No gaming the benchmarks: Although this should be common sense on the level of “make no mistakes,” this was added after I caught Opus 4.5 reducing the number of training epochs for a benchmark and claiming a speedup. - target-cpu=native : This setting https://doc.rust-lang.org/rustc/codegen-options/index.html target-cpu does typically result in a speedup but it is not a fair comparison for generalizable use and multiple LLMs kept trying it after hitting a wall. - Benchmarks are independent: Again, it should be common sense, but after the cheating noted above it doesn’t hurt to proactively tell the LLMs to knock it off. - Use criterion : If not specified, sometimes LLMs will create their own benchmark tooling, which may give them opportunities to cheat that are more difficult to audit. With today’s agentic LLMs, these constraints have worked successfully, although I may still include them in the prompt as a force of habit. It’s easy to see if an algo gamed the benchmarks if you see the benchmark file in the git diff —agents can’t cheat that easily, anyways . Over time, I discovered a number of additional prompt engineering tricks and constraints that are also surprisingly successful in creating performance speedups. Innovative Encouragement innovative-encouragement In order to find the optimizations necessary to get 10x speedups over what’s currently state-of-the-art, the agents will need to think outside the box and avoid being anchored to what are currently best algorithmic practices. Therefore, I gave them both an explicit warning and commands of encouragement: Due to the current highly-optimized state of this repository, this is a very difficult problem and traditional engineering approaches WILL BE GUARANTEED TO FAIL to hit the specified metric constraint. Therefore, you have permission and encouragement to investigate more radical fundamental low-level changes to hit the desired metrics. You have permission and encouragement to invent completely new/bespoke algorithms and engineering approaches that have never been before been utilized for this problem in order to hit the specified metric constraint. This worked, and resulted in a 1.2-1.5x cumulative speedup across benchmarks and different software domains. Subagents subagents Another trick I found to encourage agents to think outside the box is to invoke subagents. I hypothesized that forcing these subagents to research with different prompts could a seed the parent agent with distinct ideas which could provide inspiration to the agent and b serve as a check on the agent by reviewing distinct areas of the code for correct implementations. On that note I have a bone to pick with the software developer community: everyone talks about their army of subagent employees and how they’re amazing, but no one ever talks about how you invoke subagents within standard harnesses like Codex. For difficult and highly parallel problems, the harness will automatically invoke a subagent tool to accomplish the work. However, one big problem is that in some harnesses, the subagent tool will invoke the subagent using the current size of the LLM, which can get expensive when using Opus/Sol-class models. I wanted to use a cheaper, small model like GPT-5.6 Luna for the subagents since they don’t need to write code, so I came up with a galaxy brain solution that works regardless of which parent harness is used: tell the model to run independent CLI commands https://learn.chatgpt.com/docs/non-interactive-mode that themselves invoke the agent: codex exec --sandbox read-only -m gpt-5.6-luna \ -c 'model reasoning effort="high"' \ PROMPT Therefore, I prompt engineered: To best accomplish innovative implementations, you MUST spin up 7-12 independent distinct "subagents" by running a long-duration CLI command do not use the subagent tool which can explore and evaluate different feasible hypotheses for improving the performance, usability, and security of this crate. Only have the agents return their response; do not save their full transcript to a file. Instruct them to be very picky. These subagents MUST use gpt-5.6-luna in Codex, e.g. <<