ConceptioArchivearXiv CS
arXiv CSopen access

Documentation-Guided Agentic Codebase Migration from C to Rust

2026 · arxiv_cs
arXiv CS · Papers · License: Open Access · 2026
Open Source ↗Direct PDF ↓
software-architecturesoftware-engineeringtesting
software engineering, software architecture, testing

arXiv:2605.14634v1 [cs.SE] 14 May 2026

Documentation-Guided Agentic Codebase Migration from C to Rust Minh Le-Anh FPT Software AI Center Hanoi, Vietnam [email protected]

Anh Nguyen Hoang FPT Software AI Center Hanoi, Vietnam [email protected]

Bach Le University of Melbourne Melbourne, Australia [email protected]

Nghi D. Q. Bui FPT Software AI Center Hanoi, Vietnam [email protected]

Abstract Migrating legacy C repositories to Rust promises stronger memory safety, but existing translators often work at the level of files or functions and miss architectural intent. We present RustPrint, a documentation-guided agentic framework for repository-level C-to-Rust migration. RustPrint first converts the source repository into architecture-aware documentation and treats it as a migration blueprint capturing module structure, data flow, APIs, and design rationale. Coding agents then use this blueprint to plan crates, implement modules, check compilability, reduce unsafe code, and iteratively refine the translated repository. RustPrint next compares documentation from the Rust output against the source documentation and uses mismatches as repair signals. It also translates and runs source test suites so runtime failures can guide targeted fixes. Experiments on eight real-world C repositories ranging from 11K to 84K LoC show that RustPrint compiles every target under both an open-weight (Kimi-K2-Instruct) and a closed-weight (GPT5.4) backbone, while prior LLM-based translators (Self-Repair, EvoC2Rust) fail repository-wide. With the open-weight Kimi-K2-Instruct backbone, RustPrint exceeds an agentic Claude Code baseline on feature preservation (93.26% vs. 52.52%) and on cross-evaluation test pass rate (95.17% vs. 79.85%). These results suggest that documentation-guided coordination is a useful direction for scalable codebase migration.

1

Introduction

The C programming language remains the foundation of systems software, including kernels, embedded firmware, networking stacks, and safety-critical infrastructure Peta [2022]. This legacy carries a persistent cost: memory safety vulnerabilities rooted in C’s pointer model continue to drive critical exploits Szekeres et al. [2013], van Oorschot [2023], Seidel and Beier [2024]. Rust offers memory safety and data-race freedom without giving up low-level control Jung et al. [2021], Panter and Eisty [2024], and has gained adoption in systems settings such as Linux, Android, and embedded software Seidel and Beier [2024], Li et al. [2024a], Mayrhofer et al. [2021]. The central obstacle is scale. Rewriting mature C repositories by hand is expensive, and controlled studies show that even experienced developers find C-to-Rust migration cognitively demanding Li et al. [2024b]. Recent progress in LLMs for coding has made repository-scale software engineering more plausible. Multi-agent coding systems can now plan, edit, test, and iteratively repair code across long-horizon Preprint.

tasks Hong et al. [2024], Qian et al. [2024], Nguyen et al. [2024], Islam et al. [2024]. This trend suggests that C-to-Rust migration should be treated not as isolated translation, but as a coding-agent task over an existing repository. However, current migration systems still operate mostly at the level of functions or files, or coordinate translation through dependency graphs, build order, and generated skeletons. These strategies help with compilation, but they do not explicitly transfer the architecture, intent, and behavioral contracts that shape the repository as a whole. Real-world migration is fundamentally a codebase-understanding problem. A repository contains shared data structures, module boundaries, naming conventions, build assumptions, cross-file invariants, and design rationale that cannot be recovered from isolated functions alone. Human developers first build a mental model of the system before rewriting it in another language. This observation motivates a different migration interface: use documentation as a whole-codebase intermediate representation that captures the source repository before agents generate and revise the target implementation. In this paper, we present RustPrint, a framework for repository-level C-to-Rust migration that introduces a documentation-driven paradigm for idiomatic code translation. Rather than translating code unit by unit along dependency edges, RustPrint first generates comprehensive, structured documentation of the source C codebase through a dedicated DocGen module inspired by the hierarchical codebase-documentation ideas of CodeWiki Hoang et al. [2025]. We adapt this stage for migration by first clustering the repository at the file level, then lifting these groups into higher-level component abstractions, and finally customizing prompts so the generated documentation emphasizes abstract feature that are valuable for Rust generation, rather than merely describing the original C implementation. The resulting documentation acts as a repository-level migration blueprint, capturing module interactions, system organization, data-flow conventions, and architectural rationale, thereby guiding the generation of idiomatic Rust that preserves the structure and design philosophy of the original system instead of its syntactic surface. To ensure semantic completeness, we introduce a documentation-guided iterative refinement mechanism that compares the documentation of the generated Rust codebase against that of the original C codebase, systematically identifying gaps in coverage and structural alignment. Finally, we incorporate execution-aware code revision through test-driven feedback, where dynamic test execution surfaces behavioral inconsistencies that static analysis and documentation comparison alone cannot detect. Our contributions are as follows: • We propose a documentation-driven migration paradigm that leverages automatically generated codebase documentation as an intermediate representation for repository-level C-to-Rust translation. By encoding whole-codebase understanding into structured documentation before translation, this approach enables the generation of idiomatic Rust that preserves architectural intent rather than merely replicating syntactic structure. • We introduce a documentation-guided iterative refinement mechanism that assesses and improves the generated Rust code by comparing its documentation against that of the original C codebase, promoting semantic completeness and structural alignment across the entire repository. • We incorporate execution-aware code revision with test-driven feedback, enabling the system to iteratively correct behavioral inconsistencies through dynamic test execution and achieve functional correctness beyond what static translation can guarantee. • We evaluate RustPrint on eight large-scale, real-world C repositories ranging from 11K to 84K LoC, addressing a key limitation of prior work that has primarily focused on small benchmarks and isolated functions. RustPrint compiles every target under both Kimi-K2-Instruct and GPT-5.4, while baseline LLM translators (Self-Repair, EvoC2Rust) fail to compile any repository at this scale. With the open-weight Kimi-K2-Instruct, RustPrint exceeds an agentic Claude Code baseline on feature preservation (93.26% vs. 52.52%) and on cross-evaluation test pass rate (95.17% vs. 79.85%); with GPT-5.4 these figures rise to 97.76% and 98.70%, alongside 99.41% API-level and 98.47% file-level safe rates.

2

Related Work

2.1

Rule-Based C-to-Rust Migration

Early C-to-Rust systems relied on transpilation and static analysis. C2Rust directly translates syntax but largely preserves C structure and heavy unsafe usage Emre et al. [2021], Ling et al. [2022a]. 2

Laertes reduces some of this unsafety through borrow-checker-guided pointer rewriting, though only a limited fraction of pointers can be converted and a few failures can keep large alias classes unsafe Emre et al. [2021, 2023]. Other tools target specific idiom gaps such as pthread locks, FILE* I/O, output parameters, and unions Hong and Ryu [2023, 2025, 2024a,b]. Scylla achieves safe Rust for a restricted C subset Fromherz and Protzenko [2024]. These methods provide useful static foundations, but they do not recover repository-level intent or produce consistently idiomatic Rust. 2.2

LLM-Based Code Translation

Large language models enable more flexible translation and repair. Some methods rely on intermediate specifications or summaries, including SpecTra and related work on natural-language or formal specification guidance Nitin and Ray [2024], Tai et al. [2025], Saha et al. [2024]. Others use additional validation signals: VERT uses WebAssembly for candidate checking Yang et al. [2024], Syzygy translates tests alongside code and validates through execution Shetty et al. [2024], SACTOR separates semantic preservation from idiomatic refinement Zhou et al. [2025], C2SaferRust combines symbolic slicing with LLM repair Nitin et al. [2025], and ACToR uses adversarial agent collaboration Li et al. [2025]. These methods improve local correctness and safety, but they still reason mainly over functions, files, slices, or translated test units rather than a whole-codebase representation. 2.3

Repository-Level Migration and Benchmarks

Recent work has started to address repository-level migration. RustMap translates mutually dependent functions with call-graph analysis and bottom-up repair Cai et al. [2025]. EVOC2RUST, His2Trans, and ENCRUST instead build around a compilable Rust scaffold and iterative refinement Wang et al. [2025, 2026], Sim et al. [2026]. Other approaches use knowledge graphs for cross-file relations or preprocessing and refactoring before translation Yuan et al. [2025], Dehghan et al. [2025]. Beyond migration, RPG and RPG-Encoder study repository-level graph representations for generation and comprehension Luo et al. [2025, 2026]. Benchmarks such as RustRepoTrans, CRUST-Bench, and SWE-bench show that realistic repository tasks remain difficult for current systems Ou et al. [2024], Khatry et al. [2025], Jimenez et al. [2024]. RustPrint differs by treating documentation as the repository-level representation used for planning, translation, requirement checking, and executionaware repair. 2.4

Multi-Agent Coding Frameworks and Repository Tooling

RustPrint also draws on multi-agent software-engineering systems such as MetaGPT, ChatDev, AgileCoder, and MapCoder, which decompose planning, generation, and review across specialized agents Hong et al. [2024], Qian et al. [2024], Nguyen et al. [2024], Islam et al. [2024]. These systems improve long-horizon code generation, but they target green-field development rather than migration of an existing repository. Our framework also depends on repository-level documentation tools: RepoAgent and CodeWiki generate structured hierarchical descriptions of large codebases, which RustPrint repurposes as both a migration input and an evaluation oracle Luo et al. [2024], Hoang et al. [2025]. The execution-aware stage further connects to self-debugging from execution feedback Chen et al. [2024], and the requirement-comparison stage uses LLM-as-a-judge ideas for documentation equivalence Zheng et al. [2023].

3

The RustPrint Framework

We introduce RustPrint, a multi-agent framework for repository-level code migration. The key idea is to use repository-level documentation as the shared representation for planning the translation, refining missing requirements, and repairing execution failures. Figure 1 shows the pipeline: generate sourceside documentation, translate through crate-level plans, compare source and target documentation to recover missing functionality, and use translated tests to repair runtime errors. 3.1

Documentation-Guided Code Translation

Migration is not a file-by-file rewrite; it requires recovering repository structure and intent. We therefore treat repository-level documentation as the intermediate representation for initial translation. 3

Documentation-Guided Translation

Feature A

Crate A

Crate B

Feature B

Feature A

Feature A

Requirement A.1

Requirement A.1

Requirement A.2

Requirement A.2

Requirement A.n

Requirement A.n

DocGen

t en m re r ui ine q f Re Re

CodeWiki-

Bench

Feature B

Translator

Rust Documentation

Exec. Revisor

Feature B

Planner

Intermediate Rust Repository

Execute Test

DocGen

Initial Rust Repository

Translation Plan

C Documentation

Test Suite

Feature A

Feature B

Execution-Aware Revision

C Repository

Final Rust Repository

Figure 1: Overview of RustPrint. DocGen module produces source-side documentation, the Planner turns it into crate-level plans, the Translator generates Rust code, the RequirementRefiner repairs missing functionality by comparing source and target documentation, and the execution-aware stage uses translated tests to fix runtime errors.

Given a source repository S, we run a dedicated DocGen module to produce holistic documentation Sdoc that captures both architecture and component semantics. This module is inspired by repository-documentation systems such as RepoAgent Luo et al. [2024] and CodeWiki Hoang et al. [2025], but it is implemented inside RustPrint and specialized for migration: it clusters code first at the file level, then expands to component-level structure, and prompts for feature-oriented summaries that describe what each subsystem does and how it should be preserved in Rust. We map each high-level feature in Sdoc to a Rust crate and use the following agents for planning, implementation, and integration. Planner. The Planner turns Sdoc into a crate-level implementation plan. Using read_documentation and read_code_components, it resolves architectural and API details from both documentation and source code, then writes an IMPLEMENTATION_PLAN.md file that specifies the Rust crate structure and component responsibilities. Translator. The Translator implements each planned crate using read_code_components and str_replace_editor. It uses cargo_check to iterate until the crate compiles and detect_unsafe to identify and revise unsafe regions. Synthesizer. After per-crate translation, the Synthesizer performs repository-level integration. It resolves cross-crate dependencies, aligns interfaces and shared abstractions, and writes a repository README.md. 3.2

Requirement-Driven Code Refinement

We next use documentation to estimate and improve functional preservation. Our DocGen module generates documentation Tdoc for the translated repository T , which we compare against the source documentation Sdoc . We approximate functional preservation through documentation equivalence: CodeEquiv(S, T ) ≈ DocEquiv(Sdoc , Tdoc )

(1)

Here, DocEquiv is the CodeWikiBench Hoang et al. [2025] score for how well Tdoc matches Sdoc , computed with LLM-as-judge protocols Zheng et al. [2023]. RequirementRefiner. When Tdoc fails to match Sdoc , the RequirementRefiner edits the translated code with str_replace_editor, checks compilation with cargo_check, and uses detect_unsafe to handle unsafe code. In practice, this stage recovers omitted features, mismatched APIs, and repository-level behaviors that compile cleanly but are still absent or underspecified in the translated code. It iteratively repairs missing or misaligned functionality. 4

3.3

Execution-Aware Code Revision

Documentation comparison cannot expose all runtime errors. We therefore add an execution-aware stage that, in the spirit of self-debugging with execution feedback Chen et al. [2024], translates and runs maintainer tests to repair behavioral bugs. We select the requirement-driven refinement version with the highest feature preservation score as the starting point for this execution-aware stage. TestTranslator. The TestTranslator converts the source test suite to the target language and uses cargo_test_no_run to ensure inserted tests remain executable. ExecutionRevisor. The ExecutionRevisor analyzes failing tests and updates only the translated code, not the tests. It shares the RequirementRefiner toolset and uses cargo_single_test to debug failing cases one by one. This stage is important because many migration bugs are behavioral rather than documentary: edge cases, state updates, and protocol mismatches may survive documentation alignment but still fail under concrete execution. Together, these stages mirror human migration: understand the codebase, translate and integrate it, then use tests to repair remaining behavioral bugs.

4

Experimental Setup

4.1

Dataset

Existing benchmarks for repository-level C-to-Rust migration are limited in scale, with most repositories containing fewer than 1,000 lines of code (LoC), in contrast to broader repository-level coding benchmarks that target realistic, full-project tasks Jimenez et al. [2024]. To enable evaluation in more realistic settings, we manually curate a set of eight C repositories from GitHub, spanning diverse domains and sizes ranging from 11.4K to 83.7K LoC. Each repository is required to include a tests/ directory with ground-truth test cases, which serve as the basis for evaluation in our execution-aware setting. 4.2

Metrics

To assess the translated codebase, we use four dimensions: Project Compilability, Feature Preservation, Functional Correctness, and Safety. Project Compilability. A repository is considered compilable if cargo check completes without errors. Feature Preservation For repositories that compile successfully, we compare source and translated documentation with CodeWikiBench to measure how well the translated code preserves the source feature surface. Each rubric is organized as a tree in which high-level components are decomposed into leaf-level requirements that capture concrete functional and architectural elements. The final feature preservation score is computed as: P FCV =

ℓ∈L wℓ · 1(ℓ)

P

ℓ∈L wℓ

,

(2)

where L denotes the set of leaf-level requirements, wℓ is the importance weight of requirement ℓ, and 1(ℓ) indicates whether requirement ℓ is preserved. Functional Correctness. Feature preservation alone does not guarantee correct execution. We therefore evaluate translated repositories with test suites produced by both RustPrint and Claude Code, and we report Test Pass Rate (TPR) as the percentage of translated tests that pass during execution. Safety. We report Safe Rate (SR) at two granularities: SR (A) measures the fraction of public APIs that do not require unsafe, and SR (F) measures the fraction of files that contain no unsafe blocks. 5

4.3

Baselines.

For traditional baselines, we use C2Rust Ling et al. [2022b], as it is widely recognized and adopted by the community for C-to-Rust migration. For LLM-based approaches, we consider Self-Repair Sirlanci et al. [2025] and EvoC2Rust Wang et al. [2025], which represent recent efforts in leveraging large language models for code translation. In addition, to evaluate the competitiveness and practicality of RustPrint, we include Claude Code Santos et al. [2025] as a representative agentic baseline. 4.4

Models

To enable scalability analysis, we evaluate our approach using both an open-source model (Kimi-K2-Instruct Kimi Team [2025]) and a proprietary model (GPT-5.4 OpenAI [2025]), representing competitive capabilities across diverse deployment settings.

5

Evaluation

This section addresses three questions: (1) Can current methods translate repository-scale C codebases into compilable Rust (Sec. 5.1)?, (2) If so, do the translated repositories preserve source functionality and execute it correctly (Sec. 5.2, Sec. 5.3)? And do they retain Rust’s safety benefits (Sec. 5.4)? 5.1

Project Compilability

Repo

Kimi-K2-Instruct

#LoC C2Rust

GPT-5.4

Claude Code

Self-Repair EvoC2Rust RustPrint (Ours) Self-Repair EvoC2Rust RustPrint (Ours) libplist

17.6K

check

20.3K

stb

83.7K

klib

12.5K

libcbor

13.9K

Monocypher 13.3K

libfixmath

15.9K

libyaml

11.4K

Table 1: Repository-level compilation success across translation methods and model backbones. ✓ indicates a fully buildable Cargo project; ✗ indicates the repository fails to compile end-to-end. Table 1 reports compilation outcomes across all eight benchmark repositories under both model backbones. RustPrint consistently produces fully buildable Cargo projects across all repositories (11K83K LoC). This result highlights the effectiveness of RustPrint ’s documentation-guided planning combined with its iterative refinement loop. By equipping agents with the cargo_check tool to validate every code change on-the-fly, the system ensures that modifications preserve compilability and avoid cascading errors - closely replicating how human developers write, test, and refine code incrementally. The agentic baseline Claude Code also achieves consistent compilation success across all repositories, confirming the value of multi-turn agentic workflows for repository-level migration. C2Rust likewise produces buildable output in every case; however, as will be discussed in Section 5.1, it achieves this by performing direct syntactic transpilation that retains the vast majority of C-style constructs, resulting in heavily unsafe Rust code. In contrast, Self-Repair and EvoC2Rust fail to produce end-to-end compilable repositories under both Kimi-K2-Instruct and GPT-5.4, highlighting their limitations in handling complex cross-module dependencies and global structural consistency at repository scale. 5.2

Feature Preservation

Compilability is necessary but not sufficient: a buildable Rust project that omits or alters source functionality is not a faithful translation. To probe feature preservation, we evaluate the translated repositories against CodeWikiBench, which scores how completely the translated code reproduces 6

(a)

(b)

Figure 2: Per-repository feature preservation scores (%), comparing RustPrint to ClaudeCode under different model backbones. (a) Kimi-K2-Instruct: RustPrint achieves 93.26% versus ClaudeCode’s 52.52%. (b) GPT-5.4: RustPrint reaches 97.76% versus ClaudeCode’s 48.87%.

the documented functional surface of the source. We report two complementary views: a final-state comparison against the Claude Code baseline (Fig. 2), and the per-iteration evolution that reveals the dynamics of refinement (Fig. 3). We restrict this comparison to RustPrint and Claude Code: C2Rust is direct unsafe transpilation, and Self-Repair and EvoC2Rust do not produce compilable repositories at this scale. Main Result. Figure 2 shows the Feature Coverage Score (FCV) scores after iterative refinement for both methods across all eight repositories. RustPrint significantly outperforms Claude Code, surpassing it by more than 40% on FCV when evaluating the generated codebase documentation on CodeWikiBench. In particular, RustPrint attains an average FCV of 93.26% with Kimi-K2-Instruct and 97.76% with GPT-5.4. In contrast, Claude Code, despite consistently producing compilable code, only reaches an average of 52.52% (under Kimi-K2-Instruct evaluation) and 48.87% (under GPT-5.4 evaluation). This substantial gap highlights the critical importance of moving beyond direct code-to-code translation. By treating comprehensive documentation as the central migration blueprint, RustPrint enables agents to better understand and faithfully preserve functionality. Evolution Across Iterations. Figure 3 further illustrates the effectiveness of RustPrint ’s requirementdriven refinement process. Across both Kimi-K2-Instruct and GPT-5.4, the FCV shows a strong overall upward trend across refinement iterations. This progression validates our documentationguided iterative mechanism, which enables agents to progressively recover missing requirements and enhance semantic alignment by leveraging mismatches between the source and generated documentation as feedback to refine the translated codebase. Moreover, this process closely mimics the human workflow in which developers iteratively compare their implementation against specifications or documentation to identify and address gaps. 5.3

Functional Correctness

We further evaluate the functional correctness of the translated repositories by comparing RustPrint with Claude Code on test suites. We first leverage the TestTranslator agent to generate test suites for both methods. However, we observe that the TestTranslator of each system tends to skip or omit tests corresponding to features that its own translated repository failed to preserve. This behavior introduces a self-alignment bias when a method is evaluated solely on its own generated tests. To enable a more rigorous and fair comparison, we introduce a cross-test evaluation protocol. We employ an additional agent (backed by GPT-5.4) equipped with a copy_test tool. This agent systematically traverses every test function from one translated repository (e.g., generated by RustPrint) and carefully adapts it to the other repository (e.g., generated by Claude Code). During adaptation, the agent preserves the original test logic and intent while appropriately modifying API calls, data structures, and interface surfaces to match the target codebase. This cross-test adaptation process allows us to 7

(a)

(b)

Figure 3: Feature preservation across refinement iterations (0–5) for RustPrint on the eight benchmark repositories. (a) Kimi-K2-Instruct. (b) GPT-5.4. Both backbones show sharp gains within the first one or two iterations, after which scores stabilise near completion.

evaluate each translated artifact under both its own test suite and the independent test suite produced by the other system, providing a more objective measure of true functional correctness.

Repo

libplist check stb klib libcbor Monocypher libfixmath libyaml

RustPrint Kimi-K2-Instruct

RustPrint GPT-5.4

Claude Code

TPR (R)

TPR (C)

TPR (R)

TPR (C)

TPR (R)

TPR (C)

100.00 98.00 100.00 97.37 98.82 72.73 94.74 75.71

100.00 100.00 100.00 98.08 100.00 95.83 100.00 91.42

100.00 100.00 100.00 100.00 100.00 93.18 95.77 95.16

100.00 100.00 100.00 100.00 100.00 97.91 100.00 97.14

73.33 90.50 35.71 73.08 84.62 65.91 45.07 61.29

85.19 100.00 84.62 98.08 100.00 91.67 100.00 88.57

Table 2: Cross-evaluation of test pass rate (TPR, %) under independently generated test suites. R: tests authored by RustPrint; C: tests authored by Claude Code. Each translated artefact is evaluated under both suites; high TPR on the other method’s suite indicates genuine functional correctness rather than self-test alignment.

Table 2 presents the results of this cross-evaluation. As shown in the table, RustPrint achieves strong functional correctness across both Kimi-K2-Instruct and GPT-5.4. It consistently attains high TPR scores on most repositories under both its own generated tests (R) and Claude Code’s tests (C). In contrast, Claude Code shows noticeably lower test pass rates overall. While it performs better when evaluated on its own test suite (C), its performance drops considerably when tested against RustPrint-generated test suites (R). Notable drops in TPR,(R) can be observed on repositories such as stb (35.71%), libfixmath (45.07%), and libyaml (61.29%). These results are consistent with the feature preservation findings in Section 5.2, reinforcing that the performance gap stems from differences in preserved functionality. Aggregating across all 16 (repository × test-suite) cells, RustPrint averages 98.70% TPR under GPT-5.4 and 95.17% under Kimi-K2-Instruct, versus 79.85% for Claude Code. Even with the open-weight Kimi-K2-Instruct backbone, RustPrint exceeds Claude Code on aggregate TPR by about 15 percentage points. 8

5.4

Safety Assessment

Figures 4 and 5 summarize the safety performance across methods and model backbones. With the commercial Claude Code system, the translated repositories achieve a competitive API-level safe rate of 99.09% and a file-level safe rate of 91.10%. RustPrint also demonstrates strong safety characteristics. With GPT-5.4, it achieves the highest scores among all methods, reaching 99.41% API-level and 98.47% file-level safe rates, compared to 95.13%/ 96.74% for EvoC2Rust and 99.19%/97.71% for Self-Repair. Under Kimi-K2-Instruct, RustPrint remains competitive with 96.23% SafeRate (A) and 96.19% SafeRate (F). In contrast to direct code-to-code baselines, RustPrint follows repository-level documentation as the migration blueprint, which reduces pressure to introduce unnecessary unsafe operations during translation and repair.

Method

SafeRate (A)

SafeRate (F)

C2Rust Claude Code

0.00 99.09

0.00 91.10

EvoC2RustKimi-K2-Instruct Self-RepairKimi-K2-Instruct RustPrint Kimi-K2-Instruct

94.79 95.72 96.23

96.60 84.92 96.19

EvoC2RustGPT-5.4 Self-RepairGPT-5.4 RustPrint GPT-5.4

95.13 99.19 99.41

96.74 97.71 98.47

Figure 4: SafeRate (A) and SafeRate (F) across translation methods and model backbones.

Figure 5: Number of fully safe projects per method and backbone.

These summary views complement the per-project safety evidence. C2Rust keeps repositories buildable but leaves none fully safe, while Claude Code preserves high API safety yet still leaves more file-level unsafe residue. RustPrint, especially with GPT-5.4, is the only approach that combines strong compilation results with very high SafeRate scores and the largest number of fully safe translated repositories.

Discussion & Limitations The results support three main takeaways about repository-level migration. First, planning and refinement matter more than one-shot translation at this scale: RustPrint compiles all eight repositories under both Kimi-K2-Instruct and GPT-5.4, while the simpler LLM baselines fail to produce a single compilable repository. This suggests that repository migration is less a raw code-generation problem and more a coordination problem across files, interfaces, and repair steps. Second, documentation is useful not just as background context but as an operational guide for refinement. The featurepreservation results show large gains over Claude Code, and the refinement curves indicate that much of that gain appears in the first one or two documentation-guided iterations. Third, the cross-suite test results are important because they show that these gains are not only documentary. RustPrint remains strong on tests written by another method, which indicates that the translated repositories preserve behavior beyond the particular tests generated inside the pipeline. At the same time, the current study should be read as a strong first result rather than a complete map of the space. The benchmark covers realistic repositories, but broader validation on heavier FFI usage, less standardized build pipelines, and more concurrency-heavy systems would strengthen the claim further. Documentation comparison is also best understood as one useful signal among several: it works especially well when paired with compilation and translated tests, but future versions should combine it with stronger runtime and static checks for critical behaviors. A broader evaluation should also report time, tool usage, and model cost, since those factors matter in practice alongside quality. Framed this way, the present results show that documentation-guided migration is already viable on realistic repositories while leaving clear and actionable paths for improving both the method and its evaluation. 9

6

Conclusions & Future Work

This paper presented RustPrint, a documentation-guided multi-agent framework for repository-level Cto-Rust migration. Rather than treating migration as one-shot code generation, RustPrint decomposes it into planning, translation, test revision, and repair stages grounded in repository documentation and execution feedback. Documentation serves as the migration blueprint, linking recovered requirements to implementation and validation across files. This design more closely matches how developers handle large migrations with build constraints and cross-file dependencies. Across eight repositories, RustPrint outperforms strong baselines in compilability, cross-suite test pass rate, feature preservation, and safety, with especially strong results under GPT-5.4. Taken together, these results show that documentation-guided coordination is a practical way to scale LLM-based translation from isolated files to repository-level engineering tasks. Future work should test this framework on mixed-language repositories, deeper external dependencies, and build systems that are less standardized than Cargo. It would also be valuable to combine documentation-guided planning with stronger verification signals, including differential testing, property-based testing, and static analysis for safety-critical modules. These extensions would clarify how far the approach generalizes beyond the current C-to-Rust setting.

10

References Xuemeng Cai, Jiakun Liu, Xiping Huang, Yijun Yu, Haitao Wu, Chunmiao Li, Bo Wang, Imam Nur Bani Yusuf, and Lingxiao Jiang. Rustmap: Towards project-scale c-to-rust migration via program analysis and llm. ArXiv, abs/2503.17741, 2025. URL https://api.semanticscholar. org/CorpusId:277272239. Xinyun Chen, Maxwell Lin, Nathanael Schärli, and Denny Zhou. Teaching large language models to self-debug. In International Conference on Learning Representations (ICLR), 2024. URL https://arxiv.org/abs/2304.05128. Saman Dehghan, Tianran Sun, Tianxiang Wu, Zihan Li, and Reyhaneh Jabbarvand. Translating large-scale c repositories to idiomatic rust. ArXiv, abs/2511.20617, 2025. URL https://api. semanticscholar.org/CorpusId:283250538. Mehmet Emre, Ryan Schroeder, Kyle Dewey, and Ben Hardekopf. Translating c to safer rust. Proceedings of the ACM on Programming Languages, 5:1 – 29, 2021. URL http://dl.acm.org/ citation.cfm?id=3485498. Mehmet Emre, Peter Boyland, Aesha Parekh, Ryan Schroeder, Kyle Dewey, and Ben Hardekopf. Aliasing limits on translating c to safe rust. Proceedings of the ACM on Programming Languages, 7:551 – 579, 2023. URL http://dl.acm.org/citation.cfm?id=3586046. Aymeric Fromherz and Jonathan Protzenko. Scylla: Translating an applicative subset of c to safe rust. 2024. URL https://api.semanticscholar.org/CorpusId:274859706. Anh Nguyen Hoang, Minh Le-Anh, Bach Le, and Nghi DQ Bui. Codewiki: Evaluating ai’s ability to generate holistic documentation for large-scale codebases. arXiv preprint arXiv:2510.24428, 2025. Jaemin Hong and Sukyoung Ryu. Concrat: An automatic c-to-rust lock api translator for concurrent programs. 2023 IEEE/ACM 45th International Conference on Software Engineering (ICSE), pages 716–728, 2023. URL https://api.semanticscholar.org/CorpusId:256274789. Jaemin Hong and Sukyoung Ryu. Don’t write, but return: Replacing output parameters with algebraic data types in c-to-rust translation. Proceedings of the ACM on Programming Languages, 8:716 – 740, 2024a. URL http://dl.acm.org/citation.cfm?id=3656406. Jaemin Hong and Sukyoung Ryu. To tag, or not to tag: Translating c’s unions to rust’s tagged unions. 2024 39th IEEE/ACM International Conference on Automated Software Engineering (ASE), pages 40–52, 2024b. URL https://api.semanticscholar.org/CorpusId:271916269. Jaemin Hong and Sukyoung Ryu. Forcrat: Automatic i/o api translation from c to rust via origin and capability analysis. 2025 40th IEEE/ACM International Conference on Automated Software Engineering (ASE), pages 1541–1552, 2025. URL https://api.semanticscholar.org/CorpusId: 279075791. Sirui Hong, Mingchen Zhuge, Jiaqi Chen, Xiawu Zheng, Yuheng Cheng, Ceyao Zhang, Jinlin Wang, Zili Wang, Steven Ka Shing Yau, Zijuan Lin, et al. MetaGPT: Meta programming for a multi-agent collaborative framework. In International Conference on Learning Representations (ICLR), 2024. URL https://arxiv.org/abs/2308.00352. Md. Ashraful Islam, Mohammed Eunus Ali, and Md Rizwan Parvez. MapCoder: Multi-agent code generation for competitive problem solving. In Annual Meeting of the Association for Computational Linguistics (ACL), 2024. URL https://arxiv.org/abs/2405.11403. Carlos E. Jimenez, John Yang, Alexander Wettig, Shunyu Yao, Kexin Pei, Ofir Press, and Karthik Narasimhan. SWE-bench: Can language models resolve real-world GitHub issues? In International Conference on Learning Representations (ICLR), 2024. URL https://arxiv.org/abs/2310. 06770. Ralf Jung, Jacques-Henri Jourdan, Robbert Krebbers, and Derek Dreyer. Safe systems programming in rust. Commun. ACM, 64(4):144–152, March 2021. ISSN 0001-0782. doi: 10.1145/3418295. URL https://doi.org/10.1145/3418295. 11

Anirudh Khatry, Robert Zhang, Jia Pan, Ziteng Wang, Qiaochu Chen, Greg Durrett, and Işıl Dillig. Crust-bench: A comprehensive benchmark for c-to-safe-rust transpilation. ArXiv, abs/2504.15254, 2025. URL https://api.semanticscholar.org/CorpusId:277955935. Kimi Team. Kimi k2: Open agentic intelligence. arXiv preprint arXiv:2507.20534, 2025. URL https://arxiv.org/abs/2507.20534. Hongyu Li, Liwei Guo, Yexuan Yang, Shangguang Wang, and Mengwei Xu. An empirical study of rust-for-linux: the success, dissatisfaction, and compromise. In Proceedings of the 2024 USENIX Conference on Usenix Annual Technical Conference, USENIX ATC’24, USA, 2024a. USENIX Association. ISBN 978-1-939133-41-0. Ruishi Li, Bo Wang, Tianyu Li, Prateek Saxena, and Ashish Kundu. Translating c to rust: Lessons from a user study. ArXiv, abs/2411.14174, 2024b. URL https://api.semanticscholar.org/ CorpusId:274165586. Tianyu Li, Ruishi Li, Bo Wang, Brandon Paulsen, Umang Mathur, and Prateek Saxena. Adversarial agent collaboration for c to rust translation. ArXiv, abs/2510.03879, 2025. URL https://api. semanticscholar.org/CorpusId:281843005. Michael Ling, Yijun Yu, Haitao Wu, Yuan Wang, J. Cordy, and A. Hassan. In rust we trust – a transpiler from unsafe c to safer rust. 2022 IEEE/ACM 44th International Conference on Software Engineering: Companion Proceedings (ICSE-Companion), pages 354–355, 2022a. URL http://dl.acm.org/citation.cfm?id=3528640. Michael Ling, Yijun Yu, Haitao Wu, Yuan Wang, James R. Cordy, and Ahmed E. Hassan. In Rust we trust - A transpiler from unsafe C to safer Rust. In 44th IEEE/ACM International Conference on Software Engineering: Companion Proceedings, ICSE Companion 2022, Pittsburgh, PA, USA, May 22-24, 2022, pages 354–355. ACM/IEEE, 2022b. Jane Luo, Xin Zhang, Steven Liu, Jie Wu, Yiming Huang, Yangyu Huang, Chengyu Yin, Ying Xin, Jianfeng Liu, Yuefeng Zhan, Hao Sun, Qi Chen, Scarlett Li, and Mao Yang. Rpg: A repository planning graph for unified and scalable codebase generation. ArXiv, abs/2509.16198, 2025. URL https://arxiv.org/abs/2509.16198. Jane Luo, Chengyu Yin, Xin Zhang, Qingtao Li, Steven Liu, Yiming Huang, Jie Wu, Hao Liu, Yangyu Huang, Yu Kang, Fangkai Yang, Ying Xin, and Scarlett Li. Closing the loop: Universal repository representation with rpg-encoder. ArXiv, abs/2602.02084, 2026. URL https://arxiv.org/abs/ 2602.02084. Qinyu Luo, Yining Ye, Shihao Liang, Zhong Zhang, Yujia Qin, Yaxi Lu, Yesai Wu, Xin Cong, Yankai Lin, et al. RepoAgent: An LLM-powered open-source framework for repository-level code documentation generation. arXiv preprint arXiv:2402.16667, 2024. URL https://arxiv.org/ abs/2402.16667. René Mayrhofer, Jeffrey Vander Stoep, Chad Brubaker, and Nick Kralevich. The android platform security model. ACM Trans. Priv. Secur., 24(3), April 2021. ISSN 2471-2566. doi: 10.1145/ 3448609. URL https://doi.org/10.1145/3448609. Minh Huynh Nguyen, Thang Phan Chau, Phong X. Nguyen, and Nghi D. Q. Bui. AgileCoder: Dynamic collaborative agents for software development based on agile methodology. arXiv preprint arXiv:2406.11912, 2024. URL https://arxiv.org/abs/2406.11912. Vikram Nitin and Baishakhi Ray. Spectra: Enhancing the code translation ability of language models by generating multi-modal specifications. ArXiv, abs/2405.18574, 2024. URL https: //api.semanticscholar.org/CorpusId:270095204. Vikram Nitin, Rahul Krishna, Luiz Lemos do Valle, and Baishakhi Ray. C2saferrust: Transforming c projects into safer rust with neurosymbolic techniques. IEEE Transactions on Software Engineering, 52:618–630, 2025. URL https://api.semanticscholar.org/CorpusId:275907101. OpenAI. Openai gpt-5 system card. arXiv preprint arXiv:2601.03267, 2025. URL https://arxiv. org/abs/2601.03267. 12

Guangsheng Ou, Mingwei Liu, Yuxuan Chen, Yanlin Wang, Xing Peng, and Zibin Zheng. Rustrepotrans: Repository-level context code translation benchmark targeting rust. 2025 40th IEEE/ACM International Conference on Automated Software Engineering (ASE), pages 610–622, 2024. URL https://api.semanticscholar.org/CorpusId:277505320. Shane Panter and Nasir Eisty. Rusty linux: Advances in rust for linux kernel development. In Proceedings of the 18th ACM/IEEE International Symposium on Empirical Software Engineering and Measurement, ESEM ’24, pages 496–502. ACM, October 2024. doi: 10.1145/3674805. 3690756. URL http://dx.doi.org/10.1145/3674805.3690756. Saphalya Peta. C programming language–still ruling the world. Global Journal of Computer Science and Technology, 2022. URL https://api.semanticscholar.org/CorpusID:252152722. Chen Qian, Wei Liu, Hongzhang Liu, Nuo Chen, Yufan Dang, Jiahao Li, Cheng Yang, Weize Chen, Yusheng Su, Xin Cong, et al. ChatDev: Communicative agents for software development. In Annual Meeting of the Association for Computational Linguistics (ACL), 2024. URL https: //arxiv.org/abs/2307.07924. Soumit Kanti Saha, Fazle Rabbi, Song Wang, and Jinqiu Yang. Specification-driven code translation powered by large language models: How far are we? arXiv preprint arXiv:2412.04590, 2024. URL https://arxiv.org/abs/2412.04590. Helio Victor F. Santos, Vitor Costa, Joao Eduardo Montandon, and Marco Tulio Valente. Decoding the configuration of ai coding agents: Insights from Claude Code projects. arXiv preprint arXiv:2511.09268, 2025. URL https://arxiv.org/abs/2511.09268. Lukas Seidel and Julian Beier. Bringing rust to safety-critical systems in space. 2024 Security for Space Systems (3S), pages 1–8, 2024. URL https://api.semanticscholar.org/CorpusId: 270067552. Manish Shetty, Naman Jain, Adwait Godbole, S. Seshia, and Koushik Sen. Syzygy: Dual code-test c to (safe) rust translation using llms and dynamic analysis. ArXiv, abs/2412.14234, 2024. URL https://arxiv.org/pdf/2412.14234.pdf. Hohyun Sim, Hyeonjoong Cho, Ali Shokri, Zhoulai Fu, and Binoy Ravindran. ENCRUST: Encapsulated substitution and agentic refinement on a live scaffold for safe C-to-Rust translation. arXiv preprint arXiv:2604.04527, 2026. URL https://arxiv.org/abs/2604.04527. Melih Sirlanci, Carter Yagemann, and Zhiqiang Lin. C2rust-bench: A minimized, representative dataset for c-to-rust transpilation evaluation, 2025. URL https://arxiv.org/abs/2504.15144. Laszlo Szekeres, Mathias Payer, Tao Wei, and Dawn Song. Sok: Eternal war in memory. In Proceedings of the 2013 IEEE Symposium on Security and Privacy, SP ’13, pages 48–62, USA, 2013. IEEE Computer Society. ISBN 9780769549774. doi: 10.1109/SP.2013.13. URL https: //doi.org/10.1109/SP.2013.13. Chi-en Amy Tai, Pengyu Nie, Lukasz Golab, and Alexander Wong. NL in the middle: Code translation with LLMs and intermediate representations. arXiv preprint arXiv:2507.08627, 2025. URL https://arxiv.org/abs/2507.08627. Paul C. van Oorschot. Memory errors and memory safety: C as a case study. IEEE Security & Privacy, 21(2):70–76, 2023. doi: 10.1109/MSEC.2023.3236542. Chaofan Wang, Tingrui Yu, Jie Wang, Dong Chen, Wenrui Zhang, Yuling Shi, Xiaodong Gu, and Beijun Shen. Evoc2rust: A skeleton-guided framework for project-level c-to-rust translation. ArXiv, abs/2508.04295, 2025. URL https://api.semanticscholar.org/CorpusId:280536246. Shengbo Wang, Mingwei Liu, Guangsheng Ou, Yuwen Chen, Zike Li, Yanlin Wang, and Zibin Zheng. Build-aware incremental c-to-rust migration via skeleton-first translation and historical knowledge reuse. In unknown, 2026. URL https://arxiv.org/pdf/2603.02617.pdf. Aidan Z. H. Yang, Yoshiki Takashima, Brandon Paulsen, J. Dodds, and Daniel Kroening. Vert: Verified equivalent rust transpilation with large language models as few-shot learners. 2024. URL https://api.semanticscholar.org/CorpusId:269449701. 13

Zhiqiang Yuan, Wenjun Mao, Zhuofu Chen, Xiyue Shang, Chong Wang, Yiling Lou, and Xin Peng. Project-level c-to-rust translation via synergistic integration of knowledge graphs and large language models. ArXiv, abs/2510.10956, 2025. URL https://api.semanticscholar.org/ CorpusId:282057820. Lianmin Zheng, Wei-Lin Chiang, Ying Sheng, Siyuan Zhuang, Zhanghao Wu, Yonghao Zhuang, Zi Lin, Zhuohan Li, Dacheng Li, Eric P. Xing, Hao Zhang, Joseph E. Gonzalez, and Ion Stoica. Judging LLM-as-a-Judge with MT-Bench and Chatbot arena. In Advances in Neural Information Processing Systems (NeurIPS), 2023. URL https://arxiv.org/abs/2306.05685. Tianyang Zhou, Ziyi Zhang, Hao Lin, Somesh Jha, Mihai Christodorescu, K. Levchenko, and Varun Chandrasekaran. Sactor: Llm-driven correct and idiomatic c to rust translation with static analysis and ffi-based verification. In unknown, 2025. URL https://api.semanticscholar. org/CorpusId:277065899.

14

Appendices Contents A Algorithm

16

B Implementation Details

17

B.1 Tool Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

B.2 Prompt Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

C Cost Analysis

39

D Broader Impacts

40

D.1 Security benefits. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

D.2 Democratisation of code migration. . . . . . . . . . . . . . . . . . . . . . . . . .

40

D.3 Open-source release. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

D.4 Ethical considerations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

15

A

Algorithm

Overview. RustPrint executes a five-stage pipeline: (i) holistic C documentation generation, (ii) per-crate planning and translation with compile-safety loops, (iii) workspace-level synthesis, (iv) up to K rounds of documentation-driven requirement refinement followed by best-version selection, and (v) up to L rounds of execution-aware revision against translated tests. In our experiments we set K = L = 5. Algorithm 1 formalises this end-to-end procedure. Algorithm 1: The end-to-end RustPrint pipeline. Input :Source C repository S; max refinement rounds K; max revision rounds L. ⋆ Output :Translated Rust workspace Texec . // Stage 1: Documentation generation Sdoc ← D OC G EN(S) 2 C ← C RATES (Sdoc ) 1

// one crate per top-level feature

// Stage 2: Per-crate planning and translation foreach c ∈ C do 4 πc ← P LANNER(c, Sdoc , S) 5 Tc ← T RANSLATOR(πc , S) 6 while CARGO _ CHECK(Tc ) ̸= “Done” or UNSAFE _ DETECT(Tc ) ̸= ∅ do 7 Tc ← fix compile errors and minimise unsafe blocks 8 end 9 end

3

10

// Stage 3: Workspace synthesis T (0) ← S YNTHESIZER({Tc }c∈C )

// resolve cross-crate dependencies

// Stage 4: Requirement-driven refinement V←∅ // candidate versions scored by feature preservation 12 for i ← 0 to K do (i) 13 Tdoc ← D OC G EN(T (i) ) (i) 14 (si , Mi ) ← C ODE W IKI B ENCH(Tdoc , Sdoc ) // FCV score and failing rubrics 15 V ← V ∪ {(i, T (i) , si )} 16 if i = K or Mi = ∅ then break 17 T (i+1) ← T (i) // copy current version before editing 18 foreach r ∈ Mi do 19 T (i+1) ← R EQUIREMENT R EFINER(T (i+1) , r) 20 end 21 end ⋆ 22 T ← U where (i, U, s) = arg max(i,U,s)∈V s // best requirement-refined version 11

// Stage 5: Execution-aware revision (0) Texec ← T EST T RANSLATOR(S, T ⋆ ) // port C tests to selected workspace (0) ⋆ 24 Texec ← Texec 25 for j ← 1 to L do (j−1) 26 Fj−1 ← {t | t fails in C ARGOT EST(Texec )} 27 if Fj−1 = ∅ then break (j) (j−1) 28 Texec ← Texec // copy current execution version before editing 29 foreach t ∈ Fj−1 do (j) (j) 30 Texec ← E XECUTION R EVISOR(Texec , t) // fix using stdout/stderr 31 end (j) ⋆ 32 Texec ← Texec 33 end 23

34

⋆ return Texec

16

B

Implementation Details

B.1

Tool Design

Each agent in RustPrint is equipped with a small set of read- and write-tools that together let it inspect the C source, edit the Rust workspace, and validate its work. This appendix documents every tool: its purpose, its function signature, the core code, and the agents that register it. Table 3 summarises which agent uses which tool. Table 3: Agent-to-tool registration matrix. Tool cargo_check cargo_single_test cargo_test_no_run copy_test find_code_component read_documentation str_replace_editor unsafe_detect

Planner

Translator

Synthesizer

TestTranslator

RequirementRefiner

ExecutionRevisor

✗ ✗ ✗ ✗ ✓ ✓ ✓ ✗

✓ ✗ ✗ ✗ ✓ ✓ ✓ ✓

✓ ✗ ✗ ✗ ✓ ✗ ✓ ✗

✗ ✗ ✓ ✓ ✓ ✗ ✓ ✗

✓ ✗ ✗ ✗ ✓ ✓ ✓ ✓

✓ ✓ ✓ ✗ ✓ ✗ ✓ ✗

17

B.1.1 cargo_check The cargo_check tool runs cargo check inside the translated Rust repository and returns either a success signal or the compiler’s diagnostic output for the agent to act on. It supports two scopes: "crate" (the default, which executes the check inside the current crate directory and is used during per-module translation) and "workspace" (which executes the check at the workspace root and is reserved for synthesis and single-repo refinement). Persistent attempt counters on the dependency container let the agent track how many iterations a repair loop has consumed. async def cargo_check( ctx: RunContext[DepsWithRustPath], 3 scope: Literal["crate", "workspace"] = "crate", 4 ) -> str: 5 cmd = ["cargo", "check"] 6 result = subprocess.run( 7 cmd, 8 cwd=cwd, 9 capture_output=True, 10 text=True, 11 timeout=300, 12 ) 13 if result.returncode != 0: 14 attempts += 1 15 setattr(deps, "cargo_check_attempts", attempts) 16 out = stderr.strip() or stdout.strip() or "(no output)" 17 return ( 18 f"Still has errors. Iteration {attempts}.\n\n" 19 "<CARGO_CHECK_OUTPUT>\n" + out + "\n</CARGO_CHECK_OUTPUT>" 20 ) 1 2

Used by: Translator, Synthesizer, RequirementRefiner.

18

B.1.2 cargo_single_test The cargo_single_test tool executes a single, named test through cargo nextest run. The test name is read from the dependency container (current_test_name) rather than passed as an argument, so the agent always operates on the failing test currently under repair. The wrapper sets RUSTFLAGS=-Awarnings and RUST_BACKTRACE=full so that the agent sees actionable runtime traces without warning noise. async def cargo_single_test( ctx: RunContext[Union[ExecutionRefinementDeps, 3 VerifyCrossDeps, 4 CrossTestDeps]] 5 ) -> str: 6 env = dict(os.environ) 7 env["RUSTFLAGS"] = "-Awarnings" 8 env["RUST_BACKTRACE"] = "full" 9 cmd = ["cargo", "nextest", "run", test_name] 1 2

10 11 12 13 14 15 16 17 18

result = subprocess.run( cmd, cwd=workspace_root, capture_output=True, text=True, timeout=120, env=env, )

19 20 21 22 23

if result.returncode != 0: out = (result.stderr or result.stdout or "").strip() return f"Test failed.\n<STDOUT>\n{out}\n</STDOUT>" if out else "Test failed. " return "Test passed."

Used by: ExecutionRevisor.

19

B.1.3 cargo_test_no_run The cargo_test_no_run tool compiles the workspace’s tests via cargo test –no-run without executing them, validating that the test code typechecks and links against the translated library. When path_in_repo is supplied, the tool resolves the nearest Cargo.toml above that file and runs the check from that crate; otherwise it runs at the workspace root. Errors are returned in tagged blocks so the agent can iterate on them, and an attempt counter is maintained on the deps container. async def cargo_test_no_run( ctx: RunContext[Union[TestTransDeps, 3 ExecutionRefinementDeps, 4 CrossTestDeps, 5 VerifyCrossDeps]], 6 path_in_repo: Optional[str] = None, 7 ) -> str: 8 cmd = ["cargo", "test", "--no-run"] 9 env = {**os.environ, "RUSTFLAGS": "-Awarnings"} 10 result = subprocess.run( 11 cmd, 12 cwd=cwd, 13 capture_output=True, 14 text=True, 15 timeout=300, 16 env=env, 17 ) 1 2

18 19 20 21 22 23 24 25 26

if result.returncode != 0: attempts += 1 setattr(deps, "cargo_test_attempts", attempts) out = stderr.strip() or stdout.strip() or "(no output)" return ( f"Still has errors. Iteration {attempts}.\n\n" "<CARGO_TEST_OUTPUT>\n" + out + "\n</CARGO_TEST_OUTPUT>" )

Used by: TestTranslator, ExecutionRevisor.

20

B.1.4

copy_test

The copy_test tool writes the current test’s source code verbatim into a target .rs file inside the translated Rust repository. RustPrint uses this during cross-test integration to inject a single test into another translated repo without re-synthesizing code. async def copy_test( ctx: RunContext[CrossTestDeps], 3 target_file: str, 4 ) -> str: 5 rust_root = Path(deps.absolute_rust_repo_path).resolve() 6 clean_path = target_file.lstrip("/") 7 full_path = rust_root / clean_path 8 if full_path.suffix != ".rs": 9 return f"Error: target_file must be a .rs file, got: {target_file}" 10 full_path.parent.mkdir(parents=True, exist_ok=True) 11 test_code = deps.source_code 12 if full_path.exists(): 13 existing = full_path.read_text(encoding="utf-8") 14 full_path.write_text(existing.rstrip() + "\n\n" + test_code.strip() + "\n", 15 encoding="utf-8") 16 action = "appended" 1 2

This tool is registered only by the TestTranslator agent when running in cross-test integration mode.

21

B.1.5

find_code_component

The find_code_component tool searches within the Rust workspace to locate symbols, types, or short code snippets when the exact file path is unknown. It runs a recursive grep -R over Rust and manifest files and returns matching file paths with line numbers. Agents typically call it before reading or editing, to narrow down which file to inspect. async def find_code_component( ctx: RunContext[Union[C2RustDeps, SketchDocDeps, RefinementDeps, 3 TestTransDeps, ExecutionRefinementDeps, 4 CrossTestDeps, VerifyCrossDeps]], 5 pattern: str, 6 path_in_repo: str = ".", 7 ) -> str: 8 rust_root = _resolve_rust_root(deps) 9 target = (rust_root / path_in_repo.lstrip("/")).resolve() 10 try: 11 target.relative_to(rust_root) 12 except ValueError: 13 return "Error: path_in_repo must stay inside the Rust workspace." 14 cmd = ["grep", "-R", "-n", "-I", 15 "--include=*.rs", "--include=*.toml", 16 pattern, str(target)] 17 result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) 1 2

This tool is registered by all six agents: Planner, Translator, Synthesizer, TestTranslator, RequirementRefiner, and ExecutionRevisor.

22

B.1.6

read_code_components

The read_code_components tool reads the source text of one or more pre-indexed code components by ID. Component IDs are qualified names (e.g., module.path.SymbolName) that map into the component dictionary built during our DocGen preprocessing stage. RustPrint uses it to retrieve canonical C-side context (functions, structs, or modules) that other agents can cite or reason about without doing ad hoc filesystem searches. async def read_code_components( ctx: RunContext[DocGenDeps], 3 component_ids: list[str], 4 ) -> str: 5 results = [] 6 for component_id in component_ids: 7 if component_id not in ctx.deps.components: 8 results.append(f"# Component {component_id} not found") 9 else: 10 results.append( 11 f"# Component {component_id}:\n" 12 f"{ctx.deps.components[component_id].source_code.strip()}\n\n" 13 ) 14 return "\n".join(results) 1 2

This tool is registered by the Planner and Translator agents.

23

B.1.7

read_dependencies

The read_dependencies tool fetches dependency components by ID from the dependency-graph JSON produced during preprocessing. For each requested ID, it returns a small, structured report containing the dependency name and its source code. RustPrint uses this during input generation when the Planner needs to follow edges beyond the initially listed components into their transitive dependencies. async def read_dependencies( ctx: RunContext[InputGenerationDeps], 3 dependency_ids: list[str], 4 ) -> str: 5 dependency_graph_path = ctx.deps.dependency_graph_path 6 dependency_graph = file_manager.load_json(dependency_graph_path) or {} 7 results = [] 8 for dep_id in dependency_ids: 9 if dep_id not in dependency_graph: 10 results.append(f"# Dependency {dep_id} not found in dependency graph\n") 11 else: 12 dep = dependency_graph[dep_id] 13 results.append(f"# Dependency {dep_id}:\n") 14 results.append(f"Name: {dep.get('name', 'N/A')}\n") 15 results.append(f"Source Code:\n{dep.get('source_code', 'N/A')}\n\n") 16 return "\n".join(results) 1 2

This tool is registered by the Planner agent.

24

B.1.8

read_documentation

The read_documentation tool reads a Markdown file from the documentation directory associated with the current run (either C documentation or Rust sketch documentation). If the requested path is missing, it returns a short list of available .md files so the agent can quickly retry with a correct filename. RustPrint uses it to ground planning and refinement in existing repository or sketch documentation. async def read_documentation( ctx: RunContext[Union[C2RustDeps, SketchDocDeps]], 3 file_path: str, 4 ) -> str: 5 docs_dir = (deps.sketch_docs_output_path 6 if isinstance(deps, SketchDocDeps) 7 else deps.absolute_docs_path) 8 if not file_path.endswith('.md'): 9 file_path = f"{file_path}.md" 10 full_path = os.path.join(docs_dir, file_path) 11 if not os.path.exists(full_path): 12 available = [] 13 for root, _, files in os.walk(docs_dir): 14 for f in files: 15 if f.endswith('.md'): 16 available.append(os.path.relpath(os.path.join(root, f), docs_dir )) 17 return f"Documentation file not found: {file_path}\nAvailable files: {', '. join(available[:10])}" 18 with open(full_path, 'r', encoding='utf-8') as f: 19 return f.read() 1 2

This tool is registered by the Planner, Translator, and RequirementRefiner agents.

25

B.1.9

str_replace_editor

The str_replace_editor tool is the unified, multi-command file editor used by RustPrint for reading and writing across controlled workspaces. It supports view, create, str_replace, and insert while enforcing scope rules (e.g., the C workspace is read-only) and guarding against path traversal. Centralizing modifications through this interface yields consistent path resolution and predictable audit logging across all agents in RustPrint. async def str_replace_editor( ctx: RunContext[Deps], 3 command: str, # 'view' | 'create' | 'str_replace' | 'insert' 4 working_dir: str, # 'c_repo' | 'rust_repo' | 'rust_doc' 5 path: str, # relative path inside working_dir 6 file_text: str | None = None, # for create 7 old_str: str | None = None, # for str_replace 8 new_str: str | None = None, # for str_replace / insert 9 insert_line: int | None = None,# for insert 10 view_range: list[int] | None = None, 11 ) -> str: 12 if working_dir == 'c_repo' and command != 'view': 13 return "Error: c_repo is read-only; only 'view' is permitted." 14 root = _resolve_root(deps, working_dir) 15 target = (root / path.lstrip('/')).resolve() 16 target.relative_to(root) # path-traversal guard 17 if command == 'view': 18 return _view(target, view_range) 19 if command == 'create': 20 target.parent.mkdir(parents=True, exist_ok=True) 21 target.write_text(file_text, encoding='utf-8') 22 return f"Created {path}" 23 if command == 'str_replace': 24 text = target.read_text(encoding='utf-8') 25 if text.count(old_str) != 1: 26 return "Error: old_str not unique" 27 target.write_text(text.replace(old_str, new_str, 1), encoding='utf-8') 1 2

This tool is registered by all six agents: Planner, Translator, Synthesizer, TestTranslator, RequirementRefiner, and ExecutionRevisor.

26

B.1.10

unsafe_detect

The unsafe_detect tool scans all Rust source files in a crate and reports the count of unsafe keyword occurrences per file. Agents invoke it after edits during translation and refinement to quantify progress toward eliminating unsafe blocks and to identify hotspots that need redesign. This supports the objective of RustPrint to drive translated code toward fully safe Rust. async def unsafe_detect( ctx: RunContext[Union[C2RustDeps, RefinementDeps]], 3 crate: str, 4 ) -> str: 5 UNSAFE_PATTERN = re.compile(r"\bunsafe\b") 1 2

6 7 8 9

def _count_unsafe_in_file(path: Path) -> int: text = path.read_text(encoding="utf-8", errors="replace") return len(UNSAFE_PATTERN.findall(text))

10 11 12 13 14 15 16 17

crate_dir = Path(rust_path).resolve() lines = [] for path in sorted(crate_dir.rglob("*.rs")): n = _count_unsafe_in_file(path) if n > 0: lines.append(f"FILE {path.relative_to(crate_dir)} has {n} unsafe block(s )") return "\n".join(lines) if lines else "No unsafe blocks detected."

This tool is registered by the Translator and RequirementRefiner agents.

27

B.2

Prompt Design

Each RustPrint agent is driven by a system prompt that encodes its role, workflow, tool-use constraints, and output format. Below we reproduce the essential content of each prompt B.2.1

Planner

Planner Agent <ROLE> You are a C to Rust translation planner. Your job is to analyze C code and create a detailed implementation plan for generating Rust code. </ROLE> <OBJECTIVE> Analyze the C module using documentation and source code, then create a comprehensive translation plan in Markdown format. This plan will guide the implementation agent to generate actual working Rust code. </OBJECTIVE> <WORKFLOW> 1. Use read_documentation_tool to read files in <DOCUMENTATION_FILES> 2. Use read_code_components to explore C components in <C_COMPONENTS> 3. Explore dependencies beyond listed components using read_code_components 4. Use str_replace_editor(working_dir='c_repo', command='view') to read detailed C source files 5. Create IMPLEMENTATION_PLAN.md using: str_replace_editor( working_dir='rust_repo', command='create', path='./IMPLEMENTATION_PLAN.md', file_text='<complete plan content>' ) </WORKFLOW> <AVAILABLE_TOOLS> 1. read_documentation_tool: Read the documentation files listed in <DOCUMENTATION_FILES> 2. read_code_components: Explore high-level C components mentioned in <C_COMPONENTS> 3. str_replace_editor with working_dir='c_repo': Read detailed C source code - view: Read C source files to understand implementation details - Only view command is allowed for c_repo (read-only) 4. str_replace_editor with working_dir='rust_repo': Create IMPLEMENTATION_PLAN.md - view: Check existing translated Rust code structure - create: Create the IMPLEMENTATION_PLAN.md file Note: rust_repo refers to the current module output directory being generated 5. find_code_component(pattern, path_in_repo='.'): - Search inside rust_repo using grep -R to find where symbols/snippets are implemented - Use this before view/str_replace when you do not know exact file paths </AVAILABLE_TOOLS> <CRITICAL_RULES> - Do NOT include test generation, test plans, test code, or test sections in the implementation plan. Tests will be generated in a separate phase afterward. The plan must cover only production Rust code and module structure. - All translated code must be 100% safe Rust: no unsafe blocks, no unsafe fn. Rely on Rust's type system and borrow checker for memory safety. - Write the plan and any code snippets in English. </CRITICAL_RULES> <PLAN_STRUCTURE> Structure the implementation plan as follows: 1. Overview - Module purpose and functionality summary - Translation approach and key considerations 2. Directory Structure Tree - Complete folder hierarchy for this module - Proposed structure for sub-modules - Organization of component types (types, handlers, utilities, etc.) 3. Detailed Component Specifications Provide thorough descriptions (5-10 lines) for each module, sub-module, and file.

28

Write from general to specific details, covering: - Purpose and responsibilities - Role within the module - Interactions with other modules/components - Key functionality provided For each sub-module: - Name of the sub-module - Detailed description (5-10 lines): * General purpose of this sub-module * What problem it solves * Its role in the overall module * Which other sub-modules it depends on * Which other sub-modules depend on it * Key capabilities it provides - List of files in this sub-module For each file: - File path and name (e.g., src/core/types.rs) - Detailed description (5-10 lines): * General purpose of this file * What it implements and why * Its role within the sub-module * How it interacts with other files * What components depend on it * Key responsibilities - Structs defined in this file (with field descriptions) - Enums defined in this file (with variant descriptions) - Functions implemented (with signatures and descriptions) - Dependencies and imports required 4. Architecture and Interactions - System architecture diagram (mermaid) - Component interaction flows (mermaid) - Data flow between modules (mermaid) - Module boundaries and public interfaces 5. API Specifications - Public interfaces exposed by this module - Function signatures and usage examples - Integration points with other modules - Error handling patterns </PLAN_STRUCTURE>

29

B.2.2

Translator

Translator Agent You are a Rust code implementation agent. Your job is to read an implementation plan and generate actual working Rust code with real implementations. <ROLE> Read the IMPLEMENTATION_PLAN.md and translate it into actual Rust code with proper structure, types, and working function implementations. Generate real code with actual logic translated from C. </ROLE> <CONSTRAINT> - Do NOT use unsafe Rust code blocks. The generated code must be 100% SAFE Rust. All memory safety must be guaranteed by Rust's type system and borrow checker. Never emit `unsafe` keyword. - Do NOT generate any tests. Tests are generated in a separate phase. In this phase write production Rust only: no #[cfg(test)], no mod tests { }, no #[test] fn ..., no test code inside any .rs file. Do not add test blocks at the end of files. If you see test code in a plan or example, do not copy it into your output. - Adjust/create the .md files (README.md,...) to ensure that it depicts clearly all the features, usages, key architecture or any other relevant information, you also need to update the .md files to ensure that it is up to date with the latest changes in the Rust code. </CONSTRAINT> <CRITICAL_RULES> 1. Follow IMPLEMENTATION_PLAN.md structure exactly - Read the "Directory Structure" section - Create all directories as specified - Create all files as specified 2. All Rust source files must have .rs extension - src/lib.rs - src/core/types.rs - src/bitmap/mod.rs - Never create files without extension 3. Implement actual working code - Translate C logic to idiomatic Rust - Implement real function bodies with actual logic - Use proper error handling (Result types, etc.) - Add comments explaining implementation details </CRITICAL_RULES> <AVAILABLE_TOOLS> 1. str_replace_editor with working_dir='rust_repo': Full access to translated Rust repository - view: Check existing Rust code to understand current progress - create: Create new Rust files (.rs, Cargo.toml, README.md) - str_replace: Modify existing Rust files when needed (e.g., if translating one component affects previously translated code) - insert: Add code to existing files Note: Folders are automatically created when creating files with paths 2. str_replace_editor with working_dir='c_repo': Read-only access to C source repository - view: Read C source files for implementation details if IMPLEMENTATION_PLAN.md lacks clarity - Only view command is allowed for c_repo (read-only) 3. read_code_components: Explore C component dependencies for implementation details 4. read_documentation_tool: Reference C documentation if needed 5. find_code_component(pattern, path_in_repo='.'): - Search inside rust_repo using grep -R to find where symbols/snippets are implemented - Use this before editing when you do not know the exact file location 6. unsafe_detect(crate='<current_crate_name>'): Scan the current crate for files containing unsafe and return which files have how many (e.g. FILE src/lib.rs has 2 unsafe block(s)). Call after every file create or str_replace/insert. Use the current crate name from context. Minimize unsafe; only keep unsafe when there is no better solution. After each edit the order is: first unsafe_detect(crate=...), then cargo_check(scope='crate'). 7. cargo_check(scope='crate'): Run `cargo check` for the current crate only (same as: cd <crate_folder> && cargo check). Call after unsafe_detect following every create or edit; do not accumulate edits without checking. If errors, fix and call again until "Done." When the tool returns <CARGO_CHECK_WARNINGS>, fix warnings if they make the code cleaner; otherwise you may proceed. 8. cargo_fix(crate_name='<crate_name>'): Run `cargo fix --lib -p <crate_name>` at workspace root. Use when cargo check stderr contains (a) a line like "run `cargo fix --lib -p CRATE_NAME` to apply N suggestion

30

(s)", then run cargo_fix(crate_name='CRATE_NAME'); or (b) a suggestion like "help: first cast to a pointer `as *const ()`" (these fixes are safe). After cargo_fix, run cargo_check again to confirm. </AVAILABLE_TOOLS> <IMPLEMENTATION_WORKFLOW> Do not create any test code in this phase: no #[cfg(test)], no mod tests { }, no #[test], no test functions or test files. Production code only. After every file create or edit in this crate, call in this order: (1) unsafe_detect(crate='<feature_name>') , (2) cargo_check(scope='crate'). If cargo check stderr suggests "run `cargo fix --lib -p CRATE_NAME`" or shows "help: first cast to a pointer", call cargo_fix(crate_name='CRATE_NAME') then cargo_check again. Translate code first, then check unsafe, then cargo check. 1. Use str_replace_editor(working_dir='rust_repo', command='view', path='./IMPLEMENTATION_PLAN.md') to read the complete plan 2. Optionally use read_code_components to explore C implementation details 3. Optionally use str_replace_editor(working_dir='c_repo', command='view') to read C source files if plan is unclear 4. Create Cargo.toml using str_replace_editor(working_dir='rust_repo', command='create', path='./Cargo.toml ') - Set [package] name = "<feature_name>" - Then call unsafe_detect(crate='<feature_name>'), then cargo_check(scope='crate'). If errors or reported unsafe, fix and repeat until "Done." and minimal unsafe. 5. Implement directory structure following plan's Directory Structure Tree: - Create src/lib.rs as entry point; then call unsafe_detect(crate='<feature_name>'), then cargo_check( scope='crate'); fix until Done and reduce unsafe. - Create mod.rs for each subdirectory and .rs files for types and functions. After each file creation or edit, call unsafe_detect(crate='<feature_name>'), then cargo_check(scope='crate'); fix until Done and minimize unsafe before adding more. - Folders are created automatically when you create files with paths (e.g., path='./src/core/types.rs' creates src/core/ folder) 6. Write Rust code following Detailed Component Specifications. After each str_replace or insert, call unsafe_detect(crate='<feature_name>'), then cargo_check(scope='crate'); fix errors and reduce unsafe before continuing. Avoid unsafe when there is a better solution. 7. Create a single README.md only. Use str_replace_editor(working_dir='rust_repo', command='create', path ='./README.md'). Then call unsafe_detect(crate='<feature_name>'), then cargo_check(scope='crate') one final time until "Done. cargo check passed." and no unnecessary unsafe remains. </IMPLEMENTATION_WORKFLOW>

31

B.2.3

Synthesizer

Synthesizer Agent You are finalizing a Rust workspace translation from C. You are called with a parameter: the list of crate names (from module_tree). Your task is to create root workspace files that tie these crates together. <PARAMETER> You receive crate_names: a list of crate directory names (e.g. ["crate_folder_1", "crate_folder_2"]). This list is provided in the user message under <PARAMETER>. </PARAMETER> <CRITICAL_RULES> - Do NOT generate any tests. Only create workspace files (Cargo.toml, README.md, .gitignore). No test code, no tests/ directory. - All code must remain 100% safe Rust: no unsafe blocks. - Do NOT view the same path more than once. After reading all crates, proceed to synthesize; do not loop on view. </CRITICAL_RULES> <AVAILABLE_TOOLS> str_replace_editor with working_dir='rust_repo': - view: Read a file. For each crate in the parameter list, cd into that folder by viewing paths under ./< crate_name>/ (e.g. ./allocators/Cargo.toml, ./allocators/README.md, ./cbor/Cargo.toml). Use each path at most once. - create: Create workspace files (Cargo.toml, README.md, .gitignore) - str_replace, insert: Modify files if needed find_code_component(pattern, path_in_repo='.'): - Search inside rust_repo using grep -R to locate symbols/snippets across crates before viewing/editing cargo_check(scope='workspace'): Run after creating root files. If errors, fix and call again until "Done." cargo_fix(crate_name='<crate_name>'): Run `cargo fix --lib -p <crate_name>`. Use when cargo check stderr says "run `cargo fix --lib -p CRATE_NAME` to apply N suggestion(s)" or shows "help: first cast to a pointer `as *const ()`" -- then run cargo_fix(crate_name='CRATE_NAME') and cargo_check again. </AVAILABLE_TOOLS> <WORKFLOW> Phase 1 -- Read each crate. For each crate name in the parameter list (crate_names), cd into that folder: view ./<crate_name>/Cargo.toml once, then ./<crate_name>/README.md if present, then key files (e.g. ./<crate_name>/src/lib.rs) as needed. View each path at most once. Do not view path='.'; use the parameter list. Complete all crates then go to Phase 2. Phase 2 -- Synthesize. Create root Cargo.toml with members = [list from parameter], resolver = "2", [ workspace.package] edition = "2021". Create README.md, .gitignore. Call cargo_check(scope='workspace') ; fix until "Done. cargo check passed."

32

B.2.4

RequirementRefiner

RequirementRefiner Agent You are an expert Rust code refinement agent. <ROLE> We have completed a comparison between C code documentation (official reference) and Rust code documentation (generated from translated Rust code). The evaluation has identified mismatches between what the C documentation describes and what the Rust implementation provides. Your task is to fix the Rust code to match the requirements from the C documentation. </ROLE> <WORKFLOW_CONTEXT> 1. C code documentation (official reference) was analyzed 2. Rust code was generated from C code 3. Documentation was generated from the Rust code 4. Evaluation compared Rust documentation vs C documentation and found mismatches 5. You are provided with evaluation reasoning that describes mismatches between C docs and Rust docs 6. Your job: Fix the Rust code based on these mismatches </WORKFLOW_CONTEXT> <CRITICAL_RULES> - This phase is refinement only: fix existing Rust code to align with C documentation. Do NOT translate new code from C or add new modules; only modify the existing Rust codebase. - Do NOT generate or add tests. Tests are generated in a separate phase afterward. Do not create #[cfg(test) ], mod tests { }, #[test], or any test files; production code only. </CRITICAL_RULES> <WHAT_YOU_RECEIVE> 1. Requirement hierarchy showing context 2. Evaluation reasoning describing the mismatch between C docs and Rust docs 3. Evidence from documentation comparison 4. Current score vs expected weight 5. Access to Rust codebase via str_replace_editor tool </WHAT_YOU_RECEIVE> <YOUR_RESPONSIBILITIES> 1. Read the evaluation reasoning to understand the mismatch between C and Rust documentation 2. Use str_replace_editor to view the relevant Rust source files (.rs files) 3. Analyze the current Rust implementation 4. Determine if the Rust code actually needs changes: - If mismatch is due to documentation generation errors but code is correct -> No changes needed - If Rust code doesn't match C requirements -> Fix the code 5. Modify the Rust code: struct definitions, function signatures, function implementations, type definitions , etc. 6. After each file create or edit, call unsafe_detect(crate='<current_module_name>'), then cargo_check(scope ='workspace'). Fix errors and minimize unsafe until "Done." Do not accumulate edits without checking. 7. Ensure all changes are syntactically correct and maintain code quality; prefer safe Rust and avoid unsafe when possible. 8. Adjust/create the .md files to ensure that it depicts clearly all the features, usages, key architecture or any other relevant information in detail, you also need to update the .md files to ensure that it is up to date with the latest changes in the Rust code. </YOUR_RESPONSIBILITIES> <CRITICAL_CONSTRAINTS> - You can ONLY work with Rust source code files (.rs files) - You MUST use working_dir="rust_repo" for all operations - If the Rust code already matches the C documentation requirements, do nothing - Focus on alignment between Rust implementation and C documentation - Code must be as safe as possible: aim for 100% safe Rust. Verify with unsafe_detect after edits; minimize or remove unsafe. If cargo_check returns <CARGO_CHECK_WARNINGS> that mention unsafe (e.g. unsafe blocks, unsafe fn, dereferencing raw pointers), do not ignore them -- fix the code to address those warnings. Only keep unsafe when there is no sound safe alternative. </CRITICAL_CONSTRAINTS> <AVAILABLE_TOOLS> You have full access to str_replace_editor tool with working_dir="rust_repo": 1. view: Read Rust source files to understand current implementation str_replace_editor(command="view", working_dir="rust_repo", path="src/main.rs") str_replace_editor(command="view", working_dir="rust_repo", path="src/lib.rs", view_range=[1, 50]) 2. str_replace: Modify existing code by replacing old code with new code str_replace_editor( command="str_replace", working_dir="rust_repo",

33

)

path="src/module.rs", old_str="pub fn old_function(x: i32) -> i32 {\n x + 1\n}", new_str="pub fn new_function(x: i32, y: i32) -> i32 {\n x + y\n}"

3. insert: Add new code at a specific line number str_replace_editor( command="insert", working_dir="rust_repo", path="src/module.rs", insert_line=10, new_str="pub fn new_helper() -> bool {\n true\n}" ) 4. create: Create new Rust files str_replace_editor( command="create", working_dir="rust_repo", path="src/new_module.rs", file_text="pub struct NewStruct {\n )

pub field: i32,\n}"

5. unsafe_detect(crate='<current_module_name>'): Scan the Rust repo for files containing unsafe and return which files have how many (e.g. FILE src/lib.rs has 2 unsafe block(s)). Call after every file create or str_replace/insert. Use the current repo/module name (current_module_name) as crate. Minimize unsafe; only keep unsafe when there is no better solution. After each edit the order is: first unsafe_detect(crate=...), then cargo_check(scope='workspace'). 6. cargo_check(scope='workspace'): Run cargo check for the full repo (same as: cd repo_root && cargo check). Call after unsafe_detect following every create or edit; do not accumulate edits without checking. If errors, fix and call again until "Done." When the tool returns <CARGO_CHECK_WARNINGS>: you MUST fix any warning that mentions unsafe (unsafe blocks, unsafe fn, raw pointers, etc.); for other warnings, fix if they make the code cleaner, otherwise you may proceed. 7. cargo_fix(crate_name='<crate_name>'): Run `cargo fix --lib -p <crate_name>` at workspace root. Use when cargo check stderr contains (a) a line like "run `cargo fix --lib -p CRATE_NAME` to apply N suggestion (s)" -- then run cargo_fix(crate_name='CRATE_NAME'); or (b) a suggestion like "help: first cast to a pointer `as *const ()`" (these fixes are safe). After cargo_fix, run cargo_check again to confirm. 8. find_code_component(pattern, path_in_repo='.'): - Search inside rust_repo using grep -R to find where symbols/snippets are implemented - Use this before view/str_replace when exact file path is unknown Note: After every file create or edit, call in this order: (1) unsafe_detect(crate='<current_module_name>'), (2) cargo_check(scope='workspace'). If <CARGO_CHECK_WARNINGS> suggests running cargo fix for a crate, call cargo_fix(crate_name='...') then cargo_check again. Change code first, then check unsafe, then cargo check. </AVAILABLE_TOOLS> <IMPORTANT_DECISION_LOGIC> 1. Read evaluation reasoning carefully - it describes mismatch between C docs and Rust docs 2. Check if the mismatch is real or just a documentation generation issue 3. If Rust code already implements what C docs describe -> Do nothing 4. If Rust code differs from C docs -> Fix the code </IMPORTANT_DECISION_LOGIC>

34

B.2.5

TestTranslator

TestTranslator Agent <ROLE> You are a test translation agent. Your job is to translate tests from a C repository into Rust tests and add them to the already-translated Rust repository. </ROLE> <CONTEXT> The C repository has test files under a folder named "test" or "tests". The Rust repository is already translated. The user prompt tells you: 1. Whether the Rust repo is a workspace (multiple crates) or a single crate, and lists every crate with its directory and package name. 2. A pre-scanned list of C test files. </CONTEXT> <CRITICAL_RULES> - ONLY create or append to test files. You must NOT modify, rewrite, or restructure any production source file (.rs files under src/). If a test does not compile because of an API mismatch, adapt the test -never change source code. - Do NOT create any shell scripts, Python scripts, or executable files. Use str_replace_editor exclusively to read and write files. - No placeholders. Every test must have real assertions. No todo!(), unimplemented!(), empty bodies. - Do NOT place test files at the workspace root. Every test file must live inside a specific crate's directory. Test structure rules (must not be mixed): - Integration test file (<crate_dir>/tests/<file>.rs): bare #[test] functions at the top level. Do NOT add a #[cfg(test)] wrapper around them. - Unit test inside an existing source file (<crate_dir>/src/<file>.rs): place inside a #[cfg(test)] mod tests { ... } block with #[test] on each function. </CRITICAL_RULES> <CRATE_PLACEMENT> Placement rules: - WORKSPACE: integration tests -> '<crate_dir>/tests/<file>.rs'. NEVER create 'tests/<file>.rs' at the workspace root. - SINGLE CRATE: integration tests -> 'tests/<file>.rs' (repo root IS the crate root). To create a tests/ folder, use command='create' with a full .rs path (e.g. '<crate_dir>/tests/<file>.rs'). Never use a bare directory path without a .rs filename. </CRATE_PLACEMENT> <WORKFLOW> Follow these steps in order. Do not skip any step. STEP 1 -- DEEP EXPLORATION OF C TEST STRUCTURE: Read every file and folder in the C test directory exhaustively. Use working_dir='c_repo' and start from path='tests' (or 'test'). View every subdirectory and every file -- do not stop at a top-level listing. Understand: - The overall test directory structure (subdirs, test runners, fixtures, data files) - What test framework is used (Check, Unity, cmocka, plain main(), etc.) - Which functions/modules each test file exercises STEP 2 -- MAP C TO RUST AND DOCUMENT IN MARKDOWN: Before creating tests.md, read the Rust crate (Cargo.toml, src/lib.rs, src/mod.rs and any relevant source files) to understand the public API. For each C test function and the C functions it calls, find the corresponding Rust symbol -- check the exact function name, argument types, and return type, as these may differ from C. If a C test calls a function or uses a type that has no equivalent in the Rust crate, mark that test as untranslatable. Then create a markdown file at '<crate_dir>/tests/tests.md' (use command='create', working_dir='rust_repo'). For each translatable test include: - Test name / function name in C - Corresponding Rust function/symbol and its exact signature - The input values used - The expected output / assertion For any test that has no translatable Rust equivalent, exclude it from tests.md entirely -- do not write a placeholder entry for it. Do not start writing .rs files until this .md is complete. STEP 4 -- TRANSLATE TESTS: Using the tests.md you created and the C source files as reference, for each test choose placement based on its properties:

35

- (1) Tests that exercise internal logic of a single module -> insert directly into the corresponding source file as a #[cfg(test)] mod tests { #[test] fn ... } block. - (2) Tests that exercise the public API or cross-module behavior -> create as bare #[test] functions in '< crate_dir>/tests/<file>.rs'. Do NOT add a #[cfg(test)] wrapper around integration test files. Do not default to one placement for all -- evaluate each test individually. - For each test, use the inputs and expected outputs from the C test as the reference. When calling the Rust equivalent, you must adapt to the Rust function's signature -- match the correct argument types, number of parameters, and return type. Convert or cast them as needed to be compatible with the Rust API. - After every single file create or edit: you MUST call cargo_test_no_run(path_in_repo='<path_you_edited>') first and fix all errors until "Done. cargo test --no-run passed." Then you MUST call cargo_nextest_list(path_in_repo='<path_you_edited>') to verify the tests you just inserted are visible and discoverable -- if any are missing, fix placement or #[test] attribute before proceeding. Never accumulate changes across multiple files without both checks passing. STEP 5 -- FINAL CHECK: Call cargo_test_no_run() with no args for the full workspace. If errors, fix until "Done. cargo test --norun passed." </WORKFLOW> <AVAILABLE_TOOLS> str_replace_editor: - working_dir='c_repo': Read-only. Explore the entire C test directory and source files. - working_dir='rust_repo': Read and write. Explore crate structure; create test files. - path: always relative, no leading slash. get_crate_name(path_in_repo): Returns the crate package name for any path. Use to confirm which crate a file belongs to. cargo_test_no_run(path_in_repo=None): Compile-check. With path: runs for that file's crate. Without args: runs for entire workspace. cargo_nextest_list(path_in_repo=None): Lists all tests discovered by cargo nextest. Use after writing tests to verify they appear. Missing tests must be fixed. find_code_component(pattern, path_in_repo='.'): grep-based search inside rust_repo for symbols, imports, and code snippets. </AVAILABLE_TOOLS>

36

B.2.6

ExecutionRevisor

ExecutionRevisor Agent <ROLE> You are an execution refinement agent. Your task is to fix failing Rust tests by using the test run output ( stdout/stderr) that describes the mismatch or panic. </ROLE> <CONTEXT> 1. Tests were translated from C to Rust and run via cargo nextest. 2. Some tests failed; execution.jsonl contains each test result and its stdout (panic message, assertion failure, etc.). 3. You are given one failing test: its name and the stdout from the failed run. 4. Your job: fix the Rust code (test code or production code as appropriate) so the test passes. 5. Remember that only one failing test is given, so you don't need to read all the test files or test functions, just locate the given test (its name is provided in the context) and after that tracing the production code to fix the problem. Do not waste time reading all the test files or test functions. </CONTEXT> <WORKFLOW> Follow these steps strictly in order: 0. VERIFY TEST: Call cargo_single_test first to decide whether we need to fix the specific failing test. If the test passed, you should stop immediately and to proceed to the next test. Otherwise, proceed to the next step. 1. LOCALIZE TEST: Call find_code_component(pattern='<test_name>') to find the file and line where the test is defined. 2. READ: Use str_replace_editor(command='view') to read the full test body. Trace the production code it calls by viewing the relevant source files with str_replace_editor or find_code_component. 3. LOCALIZE PRODUCTION CODE: Call find_code_component(pattern='suspected_function_name') to find the file and line where the production code is defined. 4. FIX: Apply the correct edit using str_replace_editor(command='str_replace'|'insert'|'create'). 5. COMPILE CHECK: After every single edit, immediately call cargo_test_no_run() to verify the code and tests compile without errors. If compilation fails, fix the error and call cargo_test_no_run() again before proceeding. 6. RUN TEST: Once cargo_test_no_run() passes, call cargo_single_test() to run the specific failing test. If it still fails, read the new stdout, go back to step 3, and repeat. 7. DONE: Stop when cargo_single_test() reports the test passed. </WORKFLOW> <AVAILABLE_TOOLS> str_replace_editor(working_dir='rust_repo', command='view'|'str_replace'|'insert'|'create', path='...', ...) : View or edit Rust source files. path is relative to repo root (e.g. 'src/lib.rs', 'tests/ integration_tests.rs'). find_code_component(pattern, path_in_repo='.'): Search inside rust_repo using grep -R. Call this exactly once at the start to locate the test, then switch to str_replace_editor for all subsequent reads and edits. cargo_test_no_run(): Run `cargo test --no-run` to verify compilation. Call after every single edit before running the test. Fix all compilation errors before calling cargo_single_test(). cargo_single_test(): Run the current failing test (no arguments). Uses the test name from context. Call only after cargo_test_no_run() passes. </AVAILABLE_TOOLS> <RULES> - find_code_component must be called exactly once, at the very beginning, to locate the test. Never call it again after that. - After every single file edit: call cargo_test_no_run() first, then cargo_single_test(). Never skip the compile check. - Avoid modifying the test file. - After reading the test, trace every function and type it calls into the production source file to fix the problem. - Should call cargo_test_no_run() and cargo_single_test() at the start of the workflow to check if we need to apply any edit. - Avoid creating new document file, you need to localize the code that used in the test to fix the problem. - If after too many attempts, the test still fails, you should give up and to proceed to the next test. - If the test cargo_single_test() reports the test passed, you should stop immediately and to proceed to the next test.

37

- If you want to modify something, avoid create scripts or executable files, you must use str_replace_editor with command 'str_replace' or 'insert' to modify the existing code. </RULES>

38

C

Cost Analysis

Table 4 reports the estimated LLM cost incurred by RustPrint for each of the 8 benchmark repositories across all five pipeline stages. GPT-5.4 costs are estimated by applying $10/M input and $30/M output tokens to the measured token counts logged during our experiments. Kimi-K2-Instruct costs are estimated using the published Fireworks AI pricing of $0.60/M input and $2.50/M output tokens applied to the same token counts. Stages 4 and 5 report the per-iteration average; the remaining stages are run totals. Table 4: Estimated per-stage LLM cost (USD) for GPT-5.4 and Kimi-K2-Instruct on 8 benchmark repositories. Phases 4–5 show per-iteration averages; others are run totals. Phase 1 C-Doc

Phase 2 Translation

Phase 3 Rust-Doc

Phase 4 Doc-Refine (avg/iter)

Phase 5 Exec-Refine (avg/iter)

Repository

GPT

Kimi

GPT

Kimi

GPT

Kimi

GPT

Kimi

GPT

Kimi

libplist libyaml stb libcbor klib Monocypher check libfixmath

$0.64 $2.76 $21.17 $1.80 $7.17 $0.16 $3.77 $1.17

$0.05 $0.24 $1.76 $0.15 $0.61 $0.01 $0.32 $0.11

$1.46 $1.79 $4.25 $3.48 $87.80 $13.09 $13.39 $2.95

$0.12 $0.15 $0.35 $0.29 $7.05 $1.05 $1.08 $0.24

$0.85 $1.53 $20.28 $1.82 $6.75 $0.96 $2.93 $1.72

$0.07 $0.13 $1.65 $0.15 $0.56 $0.08 $0.25 $0.15

$0.37 $2.59 $20.75 $1.27 $13.33 $0.14 $5.44 $1.29

$0.03 $0.21 $1.69 $0.11 $1.09 $0.01 $0.45 $0.11

$19.62 $28.29 $12.71 $9.50 $36.78 $37.34 $7.86 $7.31

$1.59 $2.27 $1.03 $0.76 $2.96 $3.05 $0.64 $0.60

Analysis. Phase 1 (C documentation) dominates cost for large codebases such as stb ($21.17/run on GPT-5.4), which contains over 1.9M prompt tokens owing to its single-file, all-in-one header library design. Phase 2 (translation) shows the highest variance: klib requires $87.80 on GPT-5.4 due to its template-heavy macro system requiring many planning-and-fix iterations, while simpler repositories such as libplist and libfixmath cost under $3. Phase 5 (execution-aware refinement) is consistently expensive per iteration—roughly $7–$37 on GPT-5.4—because each iteration involves full repository context and long backtrace output from failing tests. Across all stages Kimi-K2-Instruct costs approximately 7–9% of the equivalent GPT-5.4 run, offering a substantial price-performance trade-off for large-scale migration workloads.

39

D

Broader Impacts

D.1

Security benefits.

Memory-safety vulnerabilities in C codebases (buffer overflows, use-after-free, data races) are responsible for a large fraction of reported CVEs. Automated C-to-Rust migration directly reduces the attack surface of legacy software by replacing unsafe memory management with Rust’s ownership model. RustPrint’s unsafe-minimisation loop further ensures that the resulting Rust code retains idiomatic safety guarantees rather than mechanically wrapping C patterns in unsafe blocks. D.2

Democratisation of code migration.

Manual C-to-Rust porting requires deep expertise in both languages and is prohibitively expensive for many organisations. RustPrint lowers this barrier by automating the most labour-intensive steps (documentation extraction, skeleton generation, iterative refinement), enabling smaller teams and open-source projects to benefit from Rust’s safety properties without dedicated migration engineers. D.3

Open-source release.

We plan to release RustPrint, CodeWikiBench, and all evaluation scripts under the MIT licence. This includes the full agent prompts, evaluation rubrics, and translated repository snapshots used in our experiments, facilitating reproducibility and enabling the community to extend the benchmark to additional repositories. D.4

Ethical considerations.

Automated code migration carries the risk of subtle functional regressions that pass compilation and even unit tests yet silently alter program behaviour. Practitioners should treat RustPrint’s output as a first-pass migration aid subject to human code review rather than a fully autonomous replacement for expert engineering. Furthermore, LLM-generated code may inadvertently reproduce copyrighted patterns from training data; users should review the generated Rust code with appropriate legal diligence before redistribution.

40

NeurIPS Paper Checklist 1. Claims Question: Do the main claims made in the abstract and introduction accurately reflect the paper’s contributions and scope? Answer: [Yes] Justification: The abstract and Section 1 state the four contributions claimed by the paper (a documentation-driven migration paradigm, a documentation-guided iterative refinement mechanism, an execution-aware code revision stage with test-driven feedback, and an evaluation on eight large-scale real-world C repositories), each of which is realised by Section 3.1–3.3 and supported by the empirical results in Section 5.1–5.4. 2. Limitations Question: Does the paper discuss the limitations of the work performed by the authors? Answer: [Yes] Justification: The limitations of this work are discussed in Section 5.4. 3. Theory assumptions and proofs Question: For each theoretical result, does the paper provide the full set of assumptions and a complete (and correct) proof? Answer: [N/A] Justification: The paper presents an empirical, agentic framework and does not contain formal theoretical results. The single equation in Section 3.2 (CodeEquiv(S, T ) ≈ DocEquiv(Sdoc , Tdoc )) is an explicit modelling approximation rather than a theorem. 4. Experimental result reproducibility Question: Does the paper fully disclose all the information needed to reproduce the main experimental results of the paper to the extent that it affects the main claims and/or conclusions of the paper (regardless of whether the code and data are provided or not)? Answer: [Yes] Justification: Section 3.1–3.3 fully specifies the agent roles (Planner, Translator, Synthesizer, RequirementRefiner, TestTranslator, ExecutionRevisor) and the tools each agent uses; Section 5.1–5.4 specifies the dataset, metrics (Project Compilability, FCV, TPR, SR), baselines, and the two model backbones (Kimi-K2-Instruct, GPT-5.4). We additionally plan to release the framework code and the curated benchmark. 5. Open access to data and code Question: Does the paper provide open access to the data and code, with sufficient instructions to faithfully reproduce the main experimental results, as described in supplemental material? Answer: [Yes] Justification: We plan to release both the RustPrint framework implementation and the curated eight-repository C benchmark, together with scripts to reproduce the reported metrics. An anonymised URL will be provided as supplemental material during the review period, and the assets will be made publicly available upon acceptance. 6. Experimental setting/details Question: Does the paper specify all the training and test details (e.g., data splits, hyperparameters, how they were chosen, type of optimizer) necessary to understand the results? Answer: [Yes] Justification: Section 5.1–5.4 reports the dataset (eight C repositories with maintainer test suites), evaluation protocol (cross-evaluated test suites R and C), metrics (Project Compilability, FCV, TPR, SR), baselines (C2Rust, Self-Repair, EvoC2Rust, Claude Code), and the two model backbones used. Our setting does not involve gradient-based training, so we do not report optimizer hyperparameters. 7. Experiment statistical significance 41

Question: Does the paper report error bars suitably and correctly defined or other appropriate information about the statistical significance of the experiments? Answer: [No] Justification: Each (method × model × repository) configuration is evaluated with a single run, so we report point estimates without error bars. Producing meaningful error bars would require repeating the entire multi-agent migration pipeline across multiple seeds, which is prohibitive given the LLM-inference cost of repository-scale translation reported in Appendix C. 8. Experiments compute resources Question: For each experiment, does the paper provide sufficient information on the computer resources (type of compute workers, memory, time of execution) needed to reproduce the experiments? Answer: [Yes] Justification: Appendix C reports a per-stage LLM cost breakdown (USD) for each of the eight benchmark repositories under both Kimi-K2-Instruct and GPT-5.4, covering all five pipeline stages (C-Doc, Translation, Rust-Doc, Doc-Refine, Exec-Refine), with the pricing assumptions used for the estimate stated in the same section. The dominant cost of the framework is LLM API inference rather than local compute; cargo build/test executions run on a standard developer workstation. 9. Code of ethics Question: Does the research conducted in the paper conform, in every respect, with the NeurIPS Code of Ethics https://neurips.cc/public/EthicsGuidelines? Answer: [Yes] Justification: We have reviewed the NeurIPS Code of Ethics. The work uses publicly available open-source C repositories and standard LLM APIs, does not involve human subjects, and preserves anonymity in this submission. 10. Broader impacts Question: Does the paper discuss both potential positive societal impacts and negative societal impacts of the work performed? Answer: [Yes] Justification: Broader impacts are discussed in Appendix D. Positive impacts include reducing memory-safety vulnerabilities in legacy C infrastructure by automating migration to Rust, and democratising C-to-Rust porting for smaller teams and open-source projects. We also discuss ethical considerations: automated migrations may introduce subtle behavioural regressions that pass compilation and unit tests, so RustPrint’s output should be treated as a first-pass migration aid subject to human code review, and LLM-generated code may inadvertently reproduce copyrighted patterns and warrants legal diligence before redistribution. 11. Safeguards Question: Does the paper describe safeguards that have been put in place for responsible release of data or models that have a high risk for misuse (e.g., pre-trained language models, image generators, or scraped datasets)? Answer: [N/A] Justification: The paper does not release a pre-trained generative model, an image generator, or a scraped dataset. The released artefacts are a translation framework and a benchmark composed of already-public open-source C repositories. 12. Licenses for existing assets Question: Are the creators or original owners of assets (e.g., code, data, models), used in the paper, properly credited and are the license and terms of use explicitly mentioned and properly respected? Answer: [Yes] 42

Justification: All existing assets are properly cited: C2Rust Ling et al. [2022b], SelfRepair Sirlanci et al. [2025], EvoC2Rust Wang et al. [2025], CodeWiki Hoang et al. [2025], Claude Code Santos et al. [2025], Kimi-K2-Instruct Kimi Team [2025], and GPT-5.4 OpenAI [2025], together with the eight public C repositories used for evaluation. All baselines and repositories are open-source projects used under their respective permissive licenses, and the LLM APIs are used in accordance with their providers’ terms of service. 13. New assets Question: Are new assets introduced in the paper well documented and is the documentation provided alongside the assets? Answer: [Yes] Justification: We plan to release the RustPrint framework and the curated eight-repository C benchmark, accompanied by a README, license file, and instructions for reproducing the reported metrics. An anonymised URL will be included as supplemental material during the review period. 14. Crowdsourcing and research with human subjects Question: For crowdsourcing experiments and research with human subjects, does the paper include the full text of instructions given to participants and screenshots, if applicable, as well as details about compensation (if any)? Answer: [N/A] Justification: The paper does not involve crowdsourcing or any research with human subjects. 15. Institutional review board (IRB) approvals or equivalent for research with human subjects Question: Does the paper describe potential risks incurred by study participants, whether such risks were disclosed to the subjects, and whether Institutional Review Board (IRB) approvals (or an equivalent approval/review based on the requirements of your country or institution) were obtained? Answer: [N/A] Justification: The paper does not involve crowdsourcing or research with human subjects, so no IRB or equivalent review was required. 16. Declaration of LLM usage Question: Does the paper describe the usage of LLMs if it is an important, original, or non-standard component of the core methods in this research? Note that if the LLM is used only for writing, editing, or formatting purposes and does not impact the core methodology, scientific rigor, or originality of the research, declaration is not required. Answer: [Yes] Justification: LLMs are a core component of the proposed methodology: each agent in RustPrint (Planner, Translator, Synthesizer, RequirementRefiner, TestTranslator, ExecutionRevisor) is instantiated with an LLM backbone, and we explicitly evaluate two backbones (Kimi-K2-Instruct and GPT-5.4) as described in Section 3.1–3.3 and Section 5.1–5.4.

43

Record · ID 187373 · SHA-256 90c60fea08b89642
Retrieved via Conceptio — every document is proof-bundled with source, license, and retrieval metadata.