back
698 comments
The byte-for-byte identical output requirement is the smartest part of this whole thing. You basically get to run the old and new pipelines side by side and diff them, which means any bug in the translation is immediately caught. Way too many rewrites fail because people try to "improve" things during the port and end up chasing phantom bugs that might be in the old code, the new code, or just behavioral differences.

Also worth noting that "translated from C++" Rust is totally fine as a starting point. You can incrementally make it more idiomatic later once the C++ side is retired. The Rust compiler will still catch whole classes of memory bugs even if the code reads a bit weird. That's the whole point.

  > Way too many rewrites fail because people try to "improve" things during the port
I'd say that porting is a great time to "improve" many things, but like you suggest, not a great time to add new features. You can do a lot of improvements while maintaining output parity. You're in the weeds, reading the code, thinking about the routines, and you have all the hindsight of having done it already. Features are great to add as comments that sketch things out but importantly this is a great time to find and recognize that maybe a subroutine is pretty inefficient. I mean the big problem in writing software is that the goal are ever evolving. You wrote the software for different goals, different constraints. So a great time to clean things up, make them more flexible, more readable, *AND TO DOCUMENT*.

I think the last one gets ignored easily but my favorite time to document code is when reading it (but the best time is when writing it). It forces you to think explicitly about what the code is doing and makes it harder for the little things to slip by. Given that Ladybird is a popular project I really do think good documentation is a way to accelerate its development. Good documentation means new people can come in and contribute faster and with fewer errors. It lowers the barrier to entry, substantially. It's also helpful for all the mere mortals who forget things

I hope, with the velocity unlocked by these tools, that more pure ports will become the norm. Before, migrations could be so costly that “improving” things “while I’m here” helped sell doing the migration at all, especially in business settings. Only to lead to more toil chasing those phantom bugs.
That reminds me of the "Strangler Fig" pattern where you replace a service by first sending the requests to both the old and new implementation so you can compare their outputs. Then only when you're confident the new service functions as expected do you actually retire the old service.
I did several web framework conversions exactly like this. Make sure the http output string matches in the new code exactly as the old code and then eventually deleted the old code with full confidence.
Works even better if you have a good test suite, which is surely the case here with Ladybird
Really like this translation approach and I had written about it just couple of days back (more from a testing and validation context). To see folks take that approach to something complex is pretty amazing! https://balanarayan.com/2026/02/20/gen-ai-time-to-focus-on-l...
> I used Claude Code and Codex for the translation. This was human-directed, not autonomous code generation. I decided what to port, in what order, and what the Rust code should look like. It was hundreds of small prompts, steering the agents where things needed to go. After the initial translation, I ran multiple passes of adversarial review, asking different models to analyze the code for mistakes and bad patterns. > The requirement from the start was byte-for-byte identical output from both pipelines. The result was about 25,000 lines of Rust, and the entire port took about two weeks. The same work would have taken me multiple months to do by hand. We’ve verified that every AST produced by the Rust parser is identical to the C++ one, and all bytecode generated by the Rust compiler is identical to the C++ compiler’s output. Zero regressions across the board

This is the way. Coding assistants are also really great at porting from one language to the other, especially if you have existing tests.

> Coding assistants are also really great at porting from one language to the other

I had a broken, one-off Perl script, a relic from the days when everyone thought Drupal was the future (long time ago). It was originally designed to migrate a site from an unmaintained internal CMS to Drupal. The CMS was ancient and it only ran in a VM for "look what we built a million years ago" purposes (I even had written permission from my ex-employer to keep that thing).

Just for a laugh, I fed this mess of undeclared dependencies and missing logic into Claude and told it to port the whole thing to Rust. It spent 80 minutes researching Drupal and coding, then "one-shotted" a functional import tool. Not only did it mirror the original design and module structure, but it also implemented several custom plugins based on hints it found in my old code comments.

It burned through a mountain of tokens, but 10/10 - would generate tens of thousands of lines of useless code again.

The Epilogue: That site has since been ported to WordPress, then ProcessWire, then rebuilt as a Node.js app. Word on the street is that some poor souls are currently trying to port it to Next.js.

Agree, and it's also such a shame that none of the AI companies actually focus on that way of using AI.

All of them are moving into the direction of "less human involved and agents do more", while what I really want is better tooling for me to work closer with AI and be better at reviewing/steering it, and be more involved. I don't want "Fire one prompt and get somewhat working code", I want a UX tailored for long sessions with back and forth, letting me leverage my skills, rather than agents trying to emulate what I already can do myself.

It was said a long time ago about computing in general, but more fitting than ever, "Augmenting the human intellect" is what we should aim for, not replacing the human intellect. IA ("Intelligence amplification") rather than AI.

But I'm guessing the target market for such tools would be much smaller, basically would require you to already understand software development, and know what you want, while all AI companies seem to target non-developers wanting to build software now. It's no-code all over again essentially.

I am learning rust myself and one of the things I definetly didn't want to do was let Claude write all the code. But I needed guidance.

I decided to create a Claude skill called "teach". When I enable it, Claude never writes any code. It just gives me hints - progressively more detailed if I am stuck. Then it reviews what I write.

I am finding it very satisfying to work this way - Rust in particular is a language where there's little space to "wing it". Most language features are interlaced with each other and having an LLM supporting me helps a lot. "Let's not declare a type for this right now, we would have to deal with several lifetime issues, let's add a note to the plan and revisit this later".

I'm a long-time Rust fan and have no idea how to respond. I think I need a lot more info about this migration, especially since Ladybird devs have been very vocal about being "anti-rust" (I guess more anti-hype, where Rust was the hype).

I don't know if it's a good fit. Not because they're writing a browser engine in Rust (good), but because Ladybird praises CPP/Swift currently and have no idea what the contributor's stance is.

At least contributing will be a lot nicer from my end, because my PR's to Ladybird have been bad due to having no CPP experience. I had no idea what I was doing.

Looks like Andreas is a mighty fine engineer, but he's even better entrepreneur. Doesn't matter if intentional or not, but he managed to create and lead a rather visible passion project, attract many contributors and use that project's momentum to detach Ladybird into a separate endeavor with much more concrete financial prospects.

The Jakt -> Swift -> Rust pivots look like the same thing on a different level. The initial change to Swift was surely motivated by potential industry support gain (i believe it was a dubious choice from purely engineering standpoint).

It's awe-inspiring to see how a person can carve a job for himself, leverage hobbyists'/hackers' interest and contributions, attract industry attention and sponsors all while doing the thing he likes (assuming, browsers are his thing) in a controlling position.

Can't fully rationalize the feeling, but all of this makes me slightly wary. Doesn't make it less cool to observe from a side, though.

> We know the result isn’t idiomatic Rust, and there’s a lot that can be simplified once we’re comfortable retiring the C++ pipeline. That cleanup will come in time.

Correct me if I’m wrong since I don’t know these two languages, but like some other languages, doing things the idiomatic way could be dramatically different. Is “cleanup” doing a lot of heavy lifting here? Could that also mean another complete rewrite from scratch?

A startup switching languages after years of development is usually a big red flag. “We are rewriting it in X” posts always preceded “We are shutting down”. I wish them luck though!

A lot of the previous calculus around refactoring and "rewrite the whole thing in a new language" is out the window now that AI is ubiquitous. Especially in situations where there is an extensive test suite.

Testing has become 10x as important as ever.

> After the initial translation, I ran multiple passes of adversarial review, asking different models to analyze the code for mistakes and bad patterns.

I feel like you just know it’s doomed. What this is saying is “I didn’t want to and cannot review the code it generated” asking models to find mistakes never works for me. It’ll find obvious patterns, a tendency towards security mistakes, but not deep logical errors.

> This is not becoming the main focus of the project. We will continue developing the engine in C++, and porting subsystems to Rust will be a sidetrack that runs for a long time.

I don't like this bit. Wouldn't it be better to decide on a memory-safe language, and then commit to it by writing all new code in Rust, or whatever. This looks like doing double the work.

> We previously explored Swift, but the C++ interop never quite got there, and platform support outside the Apple ecosystem was limited.

Why was there ever any expectation for Swift having good platform support outside Apple? This should have been (and was to me) already obvious when they originally announced moving to Swift.

> We know the result isn’t idiomatic Rust, and there’s a lot that can be simplified once we’re comfortable retiring the C++ pipeline. That cleanup will come in time.

I wonder what kind of tech debt this brings and if the trade off will be worth whatever problems they were having with C++.

From their post on Twitter in 2024 when they adopted Swift, with a comment on Rust.

My general thoughts on Rust:

- Excellent for short-lived programs that transform input A to output B

- Clunky for long-lived programs that maintain large complex object graphs

- Really impressive ecosystem

- Toxic community

https://xcancel.com/awesomekling/status/1822241531501162806

All the best to them, however this feels like yah shaving instead of focusing into delivering a browser than can become an alternative to Safari/Chrome duopoly.
Interestingly editorialized title omits “with help from AI”.
Cool, that seems like a rational choice. I hope this will help Ladybird and Servo benefit from each other in the long run, and will make both of them more likely to succeed
Someone should try this with the “Ralph Wiggum loop” approach. I suspect it would fail spectacularly, but it would be fascinating to watch.

Personally, I can’t get meaningful results unless I use the tool in a true pair-programming mode—watching it reason, plan, and execute step by step. The ability to clearly articulate exactly what you want, and how you want it done, is becoming a rare skill.

Very happy to see this. Ladybird's engineering generally seems excellent, but the decision to use Swift always seemed pretty "out there". Rust makes a whole lot more sense.
> We previously explored Swift, but the C++ interop never quite got there

But Rust doesn't have C++ interop at all?

Is there any discussion on why D or even Ada was not considered? These languages have been around for long time. If they were willing to use llm to break the initial barrier to entry for a new language, then a case can be made for these languages as well.
I know he doesn't make live coding videos anymore, but it'd be cool if Andreas showed off how this worked a little more. I'm curious how much he had to fix by hand (vs reprompting or spinning a different model or whatever).
Porting the JS parser to Rust and adopting Rust in other parts of the engine while continuing to use C++ heavily is unlikely to make Ladybird meaningfully more secure.

Attackers are surprisingly resilient to partial security.

I hope that this opens the door for collaboration between Ladybird and Servo, no need to reinvent the wheel for core components.
If this means we will get an independent state-of-the-art browser engine, I'm all for it.
Based on the origins of Rust as a tool for writing the really thorny, defensive parsers of potentially actively hostile code for firefox, I have to imagine that another web browser is the most at-home place the language could ever be.
My intuition is that they will convert to zig again when it stables. If it is possible to do it using LLM in 2 weeks for rust, then it would be the same for zig, too.

While rust is nice on paper, writting complex software in it is mentally consuming. You can not do it for a long time.

> If you look at the code, you’ll notice it has a strong “translated from C++” vibe. That’s because it is translated from C++. The top priority for this first pass is compatibility with our C++ pipeline. The Rust code intentionally mimics things like the C++ register allocation patterns so that the two compilers produce identical bytecode. Correctness is a close second. We know the result isn’t idiomatic Rust, and there’s a lot that can be simplified once we’re comfortable retiring the C++ pipeline.

Does this still get you most of the memory-safety benefits of using Rust vs C++?

If it is this easy, surely the trend is Rust output being an intermediate pass of the LLM super compiler. A security subset if you will (like other kinds of optimization), it will move from Rust specs to some deeper level of analysis and output the final executable. Some brave souls will read the intermediate Rust output (just like people used to read the assembler output from compilers) but the LLM super compiler will just translate a detailed English like spec into final executables.
> We’ve been searching for a memory-safe programming language to replace C++ in Ladybird for a while now.

The article fails to explain why. What problems (besides the obvious) have been found in which "memory-safe languages" can help. Do these problems actually explain the need of adding complexity to a project like this by adding another language?

I guess AI will be involved which, at this early point in the project would make ladybird a lot less interested (at least to me).

> We will continue developing the engine in C++, and porting subsystems to Rust will be a sidetrack that runs for a long time.

So, even though they want the code base to be in Rust, they will continue writing new code in C++ and then translating it to Rust later to remove the C++ they just added.

There must be a really good reason for this, such as Rust doesn’t interop well with C++, otherwise this seems like a poor decision.

Any word on how much more memory safe the implementation is? If passing a previous test suite is the criteria for success, what has changed, really? Are there previous memory safety tests that went from failing to passing?

I am very interested to know if this time and energy spent actually improved memory safety.

Other engineers facing the same challenges want to know!

Pardon my ignorance, but doesn't a byte-by-byte output recreation of the C++ code in Rust defeat the whole purpose of using Rust? For one, would it be idiomatic Rust anymore? Also, if there's a (non-memory related) vulnerability in the C++ code, would it be possible for that to be introduced in Rust too?
A lot of the interest in Ladybird and its parent project, SerenityOS, stemmed from the bespoke, "from scratch" approach Andreas advocated. If they're going to start vibe-coding everything, then what's the point of the top-to-bottom wheel reinvention they're doing? E.g., why even bother maintaining their own, custom XML parser instead of using any of the multitude that already exist (including in Rust) if they're ultimately going to lean heavily on AI in the course of developing it, since that inherently involves laundering existing implementations?

This project, of all of them, throwing in the towel on AI makes me fear AI abstainers have no future.

This is really YOLOing as the original author doesn't know Rust well so what happens if they hit some complex production issue LLM aren't aware of? Hiring an expensive consultant to fix that until the next LLM iteration?
Good step. It will bring many more contributors.
I wouldn't mind if one result of this was a writeup on what patterns/antipatterns are there when converting code and concepts that used to be very aligned with C++-style OOP, deep inheritance and all that jazz, to what feels natural in Rust, and how you can rephrase those concepts without loss in the substance of what you need to do.

I guess it's a long way off, since the LLM translation would need to be refactored into natural Rust first. But the value of it would be in that it's a real world project, and not a hypothetical "well, you could probably just...".

Using LibJS with servo, when?
This will be another bad decision just like with Swift. From what I heard, Rust is notoriously bad at letting people define their own structure and instead beats you up until you satisfy the borrow checker. I think it'll make development slow and unpleasant. There are people out there who enjoy that, but it's not a fit for when you need to deliver a really huge codebase in reasonable time. I remember Andreas mentioning he just wanted something like C++, but with a GC and D would be absolutely perfect for this job.
"The web platform object model inherits a lot of 1990s OOP flavor, with garbage collection, deep inheritance hierarchies, and so on. Rust’s ownership model is not a natural fit for that."

I'm confused about this part. What part of the browser did they want GC and inheritance for? I'd get it if they were writing the UI in this, but the rest of this post is about the JS engine. They weren't going to 1:1 map JS objects to Swift objects and rely on ARC to manage memory, were they?

That's a pivot, iirc they wanted to swift (I'm very glad they didn't do that). It's cool to see something like claude be useful for large scale projects like that
(Un?)ironically enough, Mr Kling was one of the people that (indirectly) first got my attention wrt LLM coding.

I watched some of his streams on the development of the JIT compiler (what this change set seems to replace) on one of his streams, and was blown away by the quality of Copilot generated suggestions/completions on an (under-represented) domain (x86 opcodes, etc). This was before Claude Code et al, and pretty early-on for LLM tooling.

Translating software that has a lot of tests is easy for LLMs. I think we'll be seeing a lot more of that in the next years. But it will take some time for people to build up more trust in these tools. Good test harnesses are a key enabler.

The inevitable cleanup that will follow this could be done the same way. Refactoring like that can be done in more bite sized chunks, which makes it easier to review what is happening and control how it is done.