Static analysis-guided agentic AI translation enables Rust as a full stack bioinformatics language
Johan Henriksson
Umeå University · Umeå Centre for Microbial Research · Integrated Science Lab · Science for Life Laboratory
q-bio.GN, cs.AI, cs.SE
Submitted: 2026-08-13
Updated: 2026-08-14
Code: https://github.com/henriksson-lab/paper_rust_translation1
License: http://creativecommons.org/licenses/by/4.0/
Importance score: 75/100
The gist: Static analysis-guided agentic AI translation enables Rust as a full stack bioinformatics language The field of bioinformatics struggles with legacy code - old code that is commonly used but may no
Terminology
Summary
Static analysis-guided agentic AI translation enables Rust as a full stack bioinformatics language
The field of bioinformatics struggles with legacy code - old code that is commonly used but may no longer have a maintainer, or may be written in an now-unfamiliar language (e.g. Perl, Fortran). This incurs maintenance cost (technical debt), but dynamically typed languages also negatively impacts the environment and fail to make use of modern hardware. Legacy code may also have security or safety problems that make it unsuited for use in clinical settings. Here we show that agentic AI, combined with static analysis, can be used to translate legacy code to the modern language Rust. We provide prompts and supporting software to aid systematic translation, and evaluate it on common software for NGS and imaging. We showcase the result on our software Bascet: Size was reduced by 80x, build time decreased by 10x, and performance of key steps improved >3x. Unix dependencies were also removed, making Bascet the only single-cell pipeline able to run on native Windows, without a container. Large-scale refactoring of bioinformatics software is thus now possible at a limited budget, enabling more complex tools to be developed.
Introduction
Bioinformatics software underpins all major biological studies today, yet funding for software is scarce, the need for software maintenance is not given enough attention, and there is a lack of workforce. While major version releases can be published anew, bug fixes typically cannot, and there is commonly little incentive for a non-author to contribute to someone else's software. This has resulted in a fragmented bioinformatics ecosystem, where it can be hard to combine software (R vs Python), be hard to run on modern computers (requiring outdated libraries), not use modern hardware efficiently, or it may no longer scale for newer large-scale datasets. When software is poorly designed (commonly due to budget or time constraints, PhDs or postdocs leaving the lab, lack of training, or change of design), issues arise that need to be circumvented when the software is used later. This is referred to as technical debt - money saved upon software conception has to be paid for later maintenance when the software is actually used (e.g., by setting up dedicated software environments or fixing the bugs). Research software has particularly high technical debt, with issues taking a long time to resolve. New challenges are now also on the horizon: (1) R, Python and Matlab consume >50x more energy than compiler or semi-compiled languages for certain workloads, making them bad for the environment. (2) Hardware is becoming scarce due to ramped up demand, requiring code to be more efficient in the coming years. (3) Computer hardware is evolving away from the use of CPUs to more efficient architectures, requiring extensive software rewriting. All of these major problems call for a rethinking of how bioinformatics research is being conducted.
Strong initiatives for improving bioinformatics code do exist; e.g., Bioconductor is an effort to increase the interoperability and quality of R-packages. While the same software may produce different results when run on different operating systems, Nextflow has narrowed this gap. However, despite the best efforts, major problems persist: It can be difficult to mix R and Python code, and the choice of language is largely based on package availability - i.e., RNA-seq analysis is almost synonymous with R while machine learning is synonymous with Python. Similarly, the library Bioformats is a cornerstone for microscopy, supporting 165 file formats (v8.5), but being written in Java, requires use of the Java virtual machine, limiting interoperability. Bioinformaticians are thus expected to learn at least two programming languages to cover most use cases. However, the increased demand for web applications also adds the need for Javascript, and high performance computing further requires knowledge of any of C, C++, Rust, Golang, Zig, or CUDA/OpenCL in the extreme case. The need to learn deeply about such a large range of topics is incompatible with the pressure to publish, and progress quickly in academia.
In this study we show how agentic AI, combined with classic static analysis, has the potential to rewrite all bioinformatics software in a single modern language. To be able to handle all use cases, this eliminates R and Python as the one language (not suited for implementing, e.g., aligners). Also, C/C++ are generally too difficult to use for most bioinformaticians due to poor tooling (e.g., no standardized build system nor docucumentation system), legacy code dependencies and unsafe language features (pointers). However, newer languages now exist. Rust was designed by Mozilla foundation to handle the requirement for performance and security in their Firefox webbrowser (https://rust-lang.org/). It has since been accepted in the Linux kernel, and since C was made popular due to Unix, Rust has by analogy the potential of becoming the next dominant language. Major companies such as Dropbox, Discord, Vercel, Cloudflare, Meta/Whatsapp have already migrated significant parts of their code to Rust, both to improve performance and security.
In summary, this study shows how Rust is able to overcome systematic ecosystem problems in bioinformatics, including version mismatches, software distribution and clinical implementation. We also demonstrate how Rust has the potential to become the only language a research group or bioinformatician ever has to master to cover the full stack
of bioinformatics.
Materials and Methods
Choice and use of AI agents
A combination of Claude and Codex was used for this study. As new versions were released during translation, this study should not be seen as a comparison of specific agentic models. In the beginning of the project, it was mainly driven by Claude code (Opus 4.7). Once Codex (20% GPT5.4 and 80% GPT5.5) was deemed more suited for translation work, it became the primary choice, especially during the early critical stages of translation. At the time of writing, GPT-5.5 (Codex) is the default, followed by Claude for resolving difficult tasks. Claude was used for all GUI (graphical user interface) programming, where the screenshots of the original software was provided as references. The translations were produced over a period of 11 weeks, using a Claude Max 20x subscription (11 weeks), and two Codex Pro subscriptions (8 weeks). Up to 90% of the limit of all three licenses were used during this period.
Choice of translation targets
The software corpuses included in this translation belong primarily to three categories: (1) Microbial and NGS software that is upstream of the current version of Bascet, (2) Software that is of relevance for image analysis and spatial omics, (3) upstream library dependencies, which in particular cover compression and file format support.
Translation
Naive prompts using Claude to translate software resulted in code that lacked most features, and the replicated features had bugs or gross simplification of algorithms. To get better translation results, a systematic check list of prompts was developed along with translation. The currently recommended prompts are included in Supplemental Material. However, both Codex and Claude have picked up implicit assumptions based on our workspaces, and the prompts may thus not be as efficient for other users. Further independent testing is needed.
The core principles that were used for all later translations (the majority) is that:
-
Each original function should be translated into one Rust function
-
No additional functions should be introduced
-
The logic of each function is independently conserved into the translated function
-
The code should follow the original code origanization, including directory structure
-
Stubs of all functions and structs are filled in, with idiomatic mapping from original code names to Rust snake case (this is the Rust naming convention)
Further prompts are injected (see Supplemental material) but these principles ensure (for Codex) that the translation is principled and conservative, enabling later audit.
Most translations were roughly done according to the following idealized steps:
-
Static analysis and scaffolding of translation (i.e., write stubs for all functions)
-
First complete translation of the code
-
Testing of the code on synthetic data (comparing to original code output)
-
Testing of the code on real data (comparing to original code output)
-
Benchmarking and speed optimization
-
Source code specific cleanup
-
Addition of idiomatic Rust API; deciding if some features should be optional (e.g., making it possible to omit command line interface)
Codex was used for the initial translation of all later corpuses as it was found to be more conservative, both in terms of verbatim translation of individual functions, but also in following the instructions. Because initial mistranslation compounds later code design, it is crucial that the first steps are done conservatively. Claude was later adopted to primarily resolve bugs that Codex could not find, or to find optimization opportunities.
Translation of C code
C-code translated according to our instructions results in non-idiomatic Rust code, where raw libc functions are frequently used. Such code is not safe and Rust cannot guarantee that the translation has no memory referencing errors, free-after-use errors, nor memory leaks. Such code should be made idiomatic after translation, but with care to not reduce speed or increase RSS in the process. The following is an example prompt used to translate jpegxr (31 kLOC):
/goal Make this code more rust idiomatic. This means data structures, functions etc need to rather use rust typical storage choices. No C types should remain and no C strings should remain. All malloc and free should be replaced by rust idiomatic memory allocation. Replace C strings with vec if not sure if unicode is safe. replace pointers with rust references when equivalent and performance is not lost(!). Use Option to represent possible null values. Whenever possible, replace data structures that are casted with named enums to avoid any need of casting. Ensure that the exceptions or errors that were originally handled are handled by translation. Do not introduce helper functions but keep translation 1-1 as far as possible. Refactor aggressively. Code need not compile at each step. Do not introduce helpers or shims, replace pointers with references optimistically and clean up later (let the code break).
Additional prompts were added during and after goal execution, e.g.:
-
I think TRUE and FALSE can be removed mechanically across all files quite easily
-
I checked the code and it looks like most *mut in function declarations can be replaced with &mut. A lot of errors will appear but they can be handlded in parallel
-
Relax faithful translation: functions related to memory allocation and deallocation need not be translated 1-1. There should be little need to manually free memory in Rust
Initial translation to non-idiomatic Rust (tested and benchmarked) took 10 hours and 15M tokens (Codex). Conversion to idiomatic Rust was performed in two sessions; first 8h with Claude, then 40 min Codex (700k tokens). To verify the API, prompts were given to another agent focused on Bioformats-rs: (paraphased) Is the API rust idiomatic
+ Refactor the API for your needs. Ensure that the API is general and not only fulfilling the needs of Bioformats
. Letting agents edit across code bases is however generally not recommended as it can unintentionally collapse API separation.
Development of static analysis support tools
Early translation attempts were made solely using agentic AI. The following errors in translation occurred commonly:
-
Expressions were swapped for no reason, i.e., a**a, or branches reordered
-
The wrong variable types were used, causing overflows
-
Order of operations was changed, causing floating point math to give different answers
-
Algorithms were replaced with naive alternatives
-
When multiple similar functions were present, the wrong function was called or
reused
for a different purpose -
Helper functions were introduced to try to make an existing function able to also solve other problems, cascading into alternative designs that later could not be extended
-
SIMD optimizations were omitted
To mitigate these problems, additional prompts were added to make the agents translate the code more verbatim. However, these prompts were ineffective for Claude, and mostly insufficient for Codex. A concern is that the agentic AI's are not precise enough in tracking the overall code structure. Tracking code structure is however something that classic algorithms can do efficiently and with high precision.
To implement such algorithms, static analysis tools were thus developed using Claude (vibe coded
). The library Treesitter (https://github.com/tree-sitter/) was used for parsing the original code into an AST (abstract syntax tree). This in turn enabled algorithmic analysis of code complexity and call graph structure. The agents are then prompted about their location which contains agent handover instructions, enabling them to figure out how to use the tools. Manual reminders were also prompted whenever the translation progress seemed stuck.
The following tools were developed (Figure 1):
-
CCC (Code complexity comparator) compares the call graph of the original code and candidate translation. In addition, it compares functions by the presence of types, symbols (numbers and strings), cyclomatic index, and logical expressions (first order logic). CCC relies on the presence of a mapping file (Rust function vs original function) which can be generated by agentic AI, or a first order guess is made. CCC also has a graphical user interface to compare the translated code vs the original but it was not extensively used for later translations.
-
tracehash aids code instrumentation. The inputs and outputs of functions are hashed, enabling rapid comparison of deviations (assuming pure functions) and difference in how many times the functions are called (higher level logic failure). tracehash also enables output of non-hashed data for selected functions, which can be used to better understand deviations once they have been detected.
-
gdbtv (gdb-translation-verifier-rs) compares the original and translated code in parallel GDB sessions. This is similar to the idea of bisimulation, used to prove equivalence of software. Unlike the first two tools, neither Claude nor Codex reached for this tool automatically, suggesting that their training prefers their first two modes of debugging.
To ensure that the tools are useful in practice, the agentic AI (primarily Claude) was instructed to add features as needed (in the original code repository) during initial use of the tools. In particular, the file describing which original function corresponds to which Rust function was improved to handle ambiguous cases; and lifetime functions (constructors and destructors) are given different treatment to relax the 1-1 correspondence (Rust does not typically need destructors, and constructors are implemented differently).
Validation and use of static analysis support tools
During development, the agents are instructed to use the static analysis tools, and both AI agents invoke them automatically (primarily CCC and tracehash). However, use of these tools turned out insufficient to remove all translation errors.
Later translation attempts focused on improving translation efficiency. After initial scaffolding, parallel agents can be used to do the translation. The translation is performed bottom-up following the call graph extracted by CCC. Qualitatively, it appears that parallelization also made the AI agents fix translation errors faster. A behavior frequently noted is that, once an error was discovered, the AI agents would give most attention to a smaller set of functions rather than perform a broad audit. This was especially the case when searching for performance problems (i.e. the agent analysis a hot spot
). However, when the translation failed to progress, the error was typically elsewhere, causing a cascade of problems. Use of pa…
Improvements for AI systems
Based on this paper, here are specific improvements to AI systems and what the improved systems can do:
1. Add static-analysis-guided translation constraints
-
Improve: Integrate AST parsing (e.g., Tree-sitter) into the agent’s translation loop to enforce 1:1 function mapping, preserve call graphs, and block the introduction of helper functions.
-
Improved system can: Translate legacy code (C, Perl, Java, Python) to Rust with verifiable structural equivalence, reducing silent logic errors like swapped branches or wrong variable types.
2. Implement automated equivalence verification
-
Improve: Add tools that hash function inputs/outputs (tracehash-style) and run parallel GDB sessions (bisimulation-style) to compare original vs. translated code automatically, not just on demand.
-
Improved system can: Detect translation bugs (e.g., floating-point order changes, integer overflows, omitted SIMD) during development, and flag them before real-data testing, cutting debugging time from weeks to hours.
3. Enable conservative, audit-driven translation modes
-
Improve: Add a “faithful translation” mode where the agent must (a) not add new functions, (b) preserve directory structure, (c) map names to snake case, and (d) pass two consecutive per-file audits before marking complete.
-
Improved system can: Produce auditable, maintainable translations that track upstream changes (e.g., openslide, minibwa) in under an hour, reducing technical debt and enabling parallel maintenance of many repositories.
4. Add memory-safety and idiom refactoring passes
-
Improve: After initial translation, run a dedicated pass that replaces raw pointers, malloc/free, and C strings with Rust references, Vec, and Option, while preserving performance (no needless copies).
-
Improved system can: Convert unsafe C-derived Rust into idiomatic, memory-safe Rust without regressions, eliminating use-after-free and memory leaks that agents currently introduce.
5. Implement parallel subagent orchestration for broad audits
-
Improve: When an error is found, force the agent to spawn parallel subagents to audit all related functions, not just the suspected hotspot, to avoid cascade failures from misdiagnosis.
-
Improved system can: Find and fix multiple translation errors simultaneously, reducing the “tunnel vision” problem where agents fix one symptom while missing the root cause elsewhere.
6. Add floating-point determinism checks
-
Improve: Add a verification step that compares p-values, gene lists, and result ordering between original and translated code, with tolerance settings, and flag any operation reordering that changes results.
-
Improved system can: Guarantee that translated bioinformatics tools produce statistically identical outputs, avoiding omitted results due to p-value cutoffs and enabling safe clinical deployment.
7. Support metaprogramming-heavy code translation
-
Improve: Extend translation to handle C++ templates, preprocessor-generated code, and build-time code generation (e.g., BLAST) by using a hybrid approach: static scaffolding for generated functions, then manual/agentic mapping to Rust generics or macros.
-
Improved system can: Translate complex codebases like BLAST, which currently fail, by treating metaprogramming as a separate translation stage rather than a 1:1 function mapping.
8. Provide cross-compilation and dependency-free output
-
Improve: Automatically strip Unix/Posix-specific calls (e.g., file permissions, pthreads) and generate native binaries for Windows, macOS (Apple M3), and Linux without containers.
-
Improved system can: Produce portable, single-binary bioinformatics tools that run natively on all major OSes, removing Conda/container dependencies and reducing distribution size by ~80x.
9. Add API-level integration for library use
-
Improve: After translation, generate idiomatic Rust APIs that split software into stages (parsing, database loading, processing, saving) and support zero-copy references, so translated code can be used as libraries, not just CLIs.
-
Improved system can: Enable pipelines like Bascet to call upstream tools as functions, eliminating startup overhead (e.g., 1,157 days saved for 100M cells) and achieving >3x speedups by avoiding per-file process launches.
10. Implement automated regression benchmarking
-
Improve: Add a benchmarking module that automatically compares speed, RSS, and output parity on real data (not synthetic), with prompts to “warm up JVM” and “test on 100M reads” to ensure fair comparisons.
-
Improved system can: Continuously validate translations against original software, catching performance regressions and correctness drift, and guiding optimization efforts to where they matter most.
Abstract
The field of bioinformatics struggles with legacy code - old code that is commonly used but may no longer have a maintainer, or may be written in an now-unfamiliar language (e.g. Perl, Fortran). This incurs maintenance cost (technical debt), but dynamically typed languages also negatively impacts the environment and fail to make use of modern hardware. Legacy code may also have security or safety problems that make it unsuited for use in clinical settings. Here we show that agentic AI, combined with static analysis, can be used to translate legacy code to the modern language Rust. We provide prompts and supporting software to aid systematic translation, and evaluate it on common software for NGS and imaging. We showcase the result on our software Bascet: Size was reduced by 80x, build time decreased by 10x, and performance of key steps improved >3x. Unix dependencies were also removed, making Bascet the only single-cell pipeline able to run on native Windows, without a container. Large-scale refactoring of bioinformatics software is thus now possible at a limited budget, enabling more complex tools to be developed.
Sources
- Exploring Scientific Debt: Harnessing AI for SATD Identification in Scientific Software
- Self-Admitted Technical Debt in Scientific Software: Prioritization, Sentiment, and Propagation Across Artifacts
- Green AI: Which Programming Language Consumes the Most?
- Thirty-seven years of relational Hoare logic: remarks on its principles and history
- AI and Memory Wall
- Small World with High Risks: A Study of Security Threats in the npm Ecosystem
- YOLOv11: An Overview of the Key Architectural Enhancements
Related papers
- Application of Single-cell Deep Learning in Elucidating the Mapping Relationship Between Visceral and Body Surface Inflammatory Patterns
- WTKO-CNN: Deep Learning Reveals Sequence Motifs Distinguishing Wild-Type and Knockout ATAC-seq Peaks
- Robust Machine Learning for Regulatory Sequence Modeling under Biological and Technical Distribution Shifts
- Stable-Shift: Biologically Structured Prediction of Transcriptional Responses to Unseen Gene Perturbations
- Evaluating Conformal Reliability of Pathway-Level Transcriptomic Signatures Under Cross-Cohort Shift in Sepsis Mortality Prediction