<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: loadingalias</title>
    <description>The latest articles on DEV Community by loadingalias (@loadingalias).</description>
    <link>https://dev.to/loadingalias</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1157360%2Fcdae5995-053b-4c46-9c87-89882978abd6.png</url>
      <title>DEV Community: loadingalias</title>
      <link>https://dev.to/loadingalias</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/loadingalias"/>
    <language>en</language>
    <item>
      <title>rscrypto v0.4.0: Verifying Constant-Time Behavior Instead of Assuming It</title>
      <dc:creator>loadingalias</dc:creator>
      <pubDate>Wed, 10 Jun 2026 03:19:51 +0000</pubDate>
      <link>https://dev.to/loadingalias/rscrypto-v040-verifying-constant-time-behavior-instead-of-assuming-it-1p2k</link>
      <guid>https://dev.to/loadingalias/rscrypto-v040-verifying-constant-time-behavior-instead-of-assuming-it-1p2k</guid>
      <description>&lt;p&gt;Every cryptography library says it's secure and performant.&lt;/p&gt;

&lt;p&gt;Very few can explain how that security is validated and how that performance is proven after every change.&lt;/p&gt;

&lt;p&gt;One of the easiest mistakes in cryptographic engineering is assuming code is constant-time because it looks constant-time. The source looks branchless. The review looks clean. The helper uses the right equality function. Then an optimization, a target specific lowering decision, an tiny refactor, or a new fast path changes the binary that actually runs. The maxim 'Don't roll your own crypto' exists for this reason, among many more.&lt;/p&gt;

&lt;p&gt;That matters a great deal because perf work and side-channel resistance are not separate worlds. If you want a crypto crate to compete w/ native libs, you end up very close to the compiler, close to the CPU, and on top of target-specific behavior. That is exactly where "looks constant-time" stops being enough, and where early Reddit/HN feedback pushed me to make the evidence story explicit.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;rscrypto&lt;/code&gt; v0.4.0, I focused on turning constant-time behavior into release evidence instead of a style assertion or general promise... as well as adding the Wycheproofs for as many primitives as possible.&lt;/p&gt;

&lt;p&gt;Anyway, this release is not "trust me, I wrote careful Rust." It's not "I read every line the LLM spit out". It's much more than that, and I hope it's the beginning of this crate earning its place in the community, in the industry.&lt;/p&gt;

&lt;p&gt;The release is: here is the manifest, here are the harnesses, here are the artifacts, here are the timing checks, here are the binary checks where the tooling supports/allows them, and here are the places where the claim does not apply yet.&lt;/p&gt;

&lt;p&gt;That is the story behind v0.4.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Constant-Time Matter?
&lt;/h2&gt;

&lt;p&gt;Timing side channels are not theoretical. If secret data can influence control flow, memory addresses, table indexes, variable-time ops, alloc behavior, or failure shape, a caller may be able to learn something from timing... that something is a risk.&lt;/p&gt;

&lt;p&gt;The classic examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a secret-dependent branch&lt;/li&gt;
&lt;li&gt;a secret-dependent table lookup&lt;/li&gt;
&lt;li&gt;an early return when a tag mismatch is found&lt;/li&gt;
&lt;li&gt;a richer error path for one kind of verification failure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cryptographic code has to be incredibly disciplined about those shapes. MAC verification, AEAD open, password verification, private-key ops, scalar multiplication, signing, and padding checks all need stricter treatment than ordinary app code.&lt;/p&gt;

&lt;p&gt;I am going to assume, if you are reading this, that you likely already know all of this. The harder part is what happens after the source looks right.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Wrong With "It Looks Constant-Time"?
&lt;/h2&gt;

&lt;p&gt;Constant-time is not a property I can declare in any meaningful way. It is a property I am going to continuously verify because this library is now core to the systems I am building.&lt;/p&gt;

&lt;p&gt;That sound pedantic until you're shipping accelerated crypto across multiple architectures. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;rscrypto&lt;/code&gt; is pure Rust, but it's not only scalar Rust. It currently ships portable fallbacks, SIMD, ASM, hardware-instruction paths, runtime dispatch, &lt;code&gt;no_std&lt;/code&gt; builds, WASM builds, and native Linux/macOS evidence lanes. I will add Windows to the target matrix as soon as I can for all of you needing Windows validation. The current bench matrix covers Intel, AMD, AWS Graviton, IBM Z, IBM POWER10, RISC-V, and Apple Silicon.&lt;/p&gt;

&lt;p&gt;That platform reach is valuable, but it makes constant-time validation much harder. An early Reddit commenter called this out, and when I sat down to sketch the actual validation plan, I nearly choked. I'd forgotten how finicky constant-time claims can actually be to validate.&lt;/p&gt;

&lt;p&gt;A source review can miss what LLVM emits for one target. A timing test on x86-64 does not prove the same behavior on aarch64. A check that passes on Apple Silicon does not tell me what happens on IBM Z. A binary-level tool that works on Linux ELF does not automatically work on Mach-O, PE/COFF, WASM, bare-metal, s390x, or little-endian POWER. The Rust backend matters too.&lt;/p&gt;

&lt;p&gt;The maintenance problem is just as real. Crypto code does not stay frozen, and this lbi is way too young to pretend that's realistic. Perf tuning moves thresholds. Dispatch changes. A helper gets reused. A public API grows a new error case. A refactor that is harmless for ordinary code can become a leak if it changes secret-dependent control flow or failure timing.&lt;/p&gt;

&lt;p&gt;Code review helps, but code review is not a release gate by itself. LLMs help find suspicious shapes, but they are even less of a release gate, IMO.&lt;/p&gt;

&lt;p&gt;So I built v0.4.0 to treat constant-time as an evidence pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define exactly what is secret and what is public&lt;/li&gt;
&lt;li&gt;define exactly which target/config is being claimed&lt;/li&gt;
&lt;li&gt;build stable harnesses for CT-critical entrypoints&lt;/li&gt;
&lt;li&gt;generate the compiled artifacts&lt;/li&gt;
&lt;li&gt;scan them&lt;/li&gt;
&lt;li&gt;run empirical timing checks&lt;/li&gt;
&lt;li&gt;run binary symbolic checks where the toolchain supports the target&lt;/li&gt;
&lt;li&gt;fail closed when required evidence is missing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is more work than saying "constant-time." It is also the only version of the claim I trust, and the only version I expect serious users to accept while I figure out what a FIPS-ready path could realistically look like here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three CT Gates
&lt;/h2&gt;

&lt;p&gt;The machine-readable source of truth is &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/ct.toml" rel="noopener noreferrer"&gt;&lt;code&gt;ct.toml&lt;/code&gt;&lt;/a&gt;. The policy lives in &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/docs/constant-time.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/constant-time.md&lt;/code&gt;&lt;/a&gt;. The tooling lives under &lt;a href="https://github.com/loadingalias/rscrypto/tree/main/tools" rel="noopener noreferrer"&gt;&lt;code&gt;tools/&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/loadingalias/rscrypto/tree/main/scripts/ct" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The hard local gate is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just ct-full
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That builds CT artifacts, validates manifest coverage, runs DudeCT cases, runs BINSEC where the target policy requires it, and emits release-style reports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gate 1: Artifact Review + Heuristic Scans
&lt;/h3&gt;

&lt;p&gt;The first gate is deliberately simple. &lt;/p&gt;

&lt;p&gt;It builds stable CT harnesses from &lt;a href="https://github.com/loadingalias/rscrypto/tree/main/tools/ct-harness" rel="noopener noreferrer"&gt;&lt;code&gt;tools/ct-harness&lt;/code&gt;&lt;/a&gt;, captures provenance, emits LLVM IR, assembly, object disassembly, symbol maps, artifact hashes, and evidence indexes, then validates the result against the manifest.&lt;/p&gt;

&lt;p&gt;The scripts involved include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/artifacts.sh" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/artifacts.sh&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/asm_heuristics.py" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/asm_heuristics.py&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/validate.py" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/validate.py&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This catches boring but dangerous problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing artifacts&lt;/li&gt;
&lt;li&gt;missing manifest coverage&lt;/li&gt;
&lt;li&gt;unexpected calls&lt;/li&gt;
&lt;li&gt;suspicious branches&lt;/li&gt;
&lt;li&gt;suspicious indexed loads&lt;/li&gt;
&lt;li&gt;panic or allocation paths in CT-critical leaves&lt;/li&gt;
&lt;li&gt;changed symbols that need review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gate does not prove constant-time behavior. It gives me and reviewers the compiled evidence and blocks clear regressions.&lt;/p&gt;

&lt;p&gt;That matters because the source is obviously not the artifact that runs in prod. The binary is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gate 2: DudeCT Validation
&lt;/h3&gt;

&lt;p&gt;The second gate is empirical timing evidence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/loadingalias/rscrypto/tree/main/tools/ct-dudect" rel="noopener noreferrer"&gt;&lt;code&gt;tools/ct-dudect&lt;/code&gt;&lt;/a&gt; runs fixed-vs-random or valid-vs-invalid timing tests for manifest-declared cases. &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/dudect.sh" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/dudect.sh&lt;/code&gt;&lt;/a&gt; runs the cases, and &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/dudect_report.py" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/dudect_report.py&lt;/code&gt;&lt;/a&gt; normalizes the output.&lt;/p&gt;

&lt;p&gt;DudeCT is useful because it catches a different class of failure than static review. If the compiled code or the platform creates a measurable timing distinction between the two classes, the release gate should fail.&lt;/p&gt;

&lt;p&gt;The wording here matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No leakage detected for this configuration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not the same as "proved constant-time forever."&lt;/p&gt;

&lt;p&gt;DudeCT is statistical evidence for a specific configuration. The exact compiler, LLVM backend, target triple, CPU/features, profile, panic mode, enabled features, dependency lockfile, and physical runner matter here.&lt;/p&gt;

&lt;p&gt;If a required DudeCT case is missing, times out, crashes, or crosses the configured leakage threshold, &lt;code&gt;ct-full&lt;/code&gt; fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gate 3: BINSEC
&lt;/h3&gt;

&lt;p&gt;The third gate is binary-level symbolic checking with BINSEC's &lt;code&gt;checkct&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/loadingalias/rscrypto/tree/main/tools/ct-binsec-harness" rel="noopener noreferrer"&gt;&lt;code&gt;tools/ct-binsec-harness&lt;/code&gt;&lt;/a&gt; exposes small CT-critical kernels. &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/scripts/ct/binsec.py" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/ct/binsec.py&lt;/code&gt;&lt;/a&gt; runs BINSEC directly rather than delegating the policy to a generic wrapper.&lt;/p&gt;

&lt;p&gt;This is a direct integration. The &lt;code&gt;rscrypto&lt;/code&gt; manifest owns the kernels, target policies, assumptions, required status, and evidence artifacts. A wrapper &lt;code&gt;cargo check-ct&lt;/code&gt; was the wrong abstraction here; the release claim has to be owned by the crate manifest.&lt;/p&gt;

&lt;p&gt;BINSEC is aimed at small, analyzable leaf kernels: constant-time equality, secret selection, Poly1305/GHASH/POLYVAL style leaves, AES round leaves, Ascon tag paths, Curve25519 helpers, Ed25519 digit helpers, and bounded RSA private-operation helpers.&lt;/p&gt;

&lt;p&gt;It is not used as a "whole public API" verifier. A full API often includes parsing, allocation, dispatch, conversion, and error handling. Those paths still need review, artifacts, heuristics, tests, fuzzing, and timing evidence, but they are not always tractable symbolic execution targets.&lt;/p&gt;

&lt;p&gt;For Linux &lt;code&gt;x86-64&lt;/code&gt; and Linux &lt;code&gt;aarch64&lt;/code&gt; lanes, BINSEC is part of the current CT evidence where the workflow supports the object/ISA path.&lt;/p&gt;

&lt;p&gt;For some other lanes, it is not possible today. RISC-V, s390x, little-endian POWER, macOS Mach-O, Windows PE/COFF, WASM, and bare-metal all need separate support, reduced kernels, different object handling, or engine specific evidence before I will make the same bin check claim. BINSEC alone is not enough there, and in some cases it is not compatible with the object format or ISA path yet. I will continue to explore and work on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Multiple Independent Checks Exist
&lt;/h2&gt;

&lt;p&gt;Security validation should fail closed.&lt;/p&gt;

&lt;p&gt;No single gate is enough.&lt;/p&gt;

&lt;p&gt;Artifact review catches missing coverage and suspicious compiled shapes. DudeCT catches timing behavior the static pass may not understand. BINSEC gives stronger binary evidence for small kernels where symbolic analysis is practical.&lt;/p&gt;

&lt;p&gt;The overlap is intentional. I do not want one green check to create false confidence.&lt;/p&gt;

&lt;p&gt;I also do not have a FIPS lab budget. &lt;code&gt;rscrypto&lt;/code&gt; is not a FIPS 140-3 validated module; it's not been audited by a third party. Pretending otherwise would be bullshit, and worse, technically useless. I am obviously really interested in changing this, but this is what I can do in the meantime: &lt;/p&gt;

&lt;p&gt;Build the kind of evidence pipeline a serious review needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact claims&lt;/li&gt;
&lt;li&gt;exact targets&lt;/li&gt;
&lt;li&gt;exact binaries&lt;/li&gt;
&lt;li&gt;reproducible artifacts&lt;/li&gt;
&lt;li&gt;current benchmark data&lt;/li&gt;
&lt;li&gt;public limitations&lt;/li&gt;
&lt;li&gt;release gates that fail when evidence is missing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a formal validation path or third-party audit becomes available, this work makes that conversation cleaner... but it obviously doesn't replace it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What v0.4.0 Means
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rscrypto&lt;/code&gt; v0.4.0 is the first release where I am comfortable leading with the constant-time evidence story instead of treating it as a paragraph in the README.&lt;/p&gt;

&lt;p&gt;This release adds or hardens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/ct.toml" rel="noopener noreferrer"&gt;&lt;code&gt;ct.toml&lt;/code&gt;&lt;/a&gt; as the source of truth for CT-critical surfaces, target policy, DudeCT cases, and BINSEC kernels&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;just ct-full&lt;/code&gt; as the local full evidence gate&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/.github/workflows/ct.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;.github/workflows/ct.yaml&lt;/code&gt;&lt;/a&gt; for hosted CT evidence lanes&lt;/li&gt;
&lt;li&gt;artifact/provenance capture, LLVM IR, assembly, object disassembly, symbol maps, and heuristic scans&lt;/li&gt;
&lt;li&gt;manifest-driven DudeCT cases&lt;/li&gt;
&lt;li&gt;manifest-driven BINSEC kernel rows where the target/tooling supports them&lt;/li&gt;
&lt;li&gt;a dedicated RSA gate through &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/.github/workflows/rsa.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;.github/workflows/rsa.yaml&lt;/code&gt;&lt;/a&gt;, including Miri and leakage regression artifacts&lt;/li&gt;
&lt;li&gt;weekly validation covering the broader quality stack: normal CI, feature matrix, Miri, fuzzing, fuzz corpus replay, CT, and coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current public CT boundary is intentionally narrow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux &lt;code&gt;x86-64&lt;/code&gt;: artifact/provenance review, LLVM IR/ASM/object heuristics, DudeCT, and BINSEC on AMD Zen4, AMD Zen5, Intel Ice Lake, and Intel Sapphire Rapids&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;aarch64&lt;/code&gt;: artifact/provenance review, LLVM IR/ASM/object heuristics, DudeCT, and BINSEC on AWS Graviton3 and Graviton4&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;riscv64gc&lt;/code&gt;: artifact/provenance review, LLVM IR/ASM/object heuristics, and DudeCT on the RISE RISC-V lane; BINSEC is not claimed today&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;s390x&lt;/code&gt;: artifact/provenance review, LLVM IR/ASM/object heuristics, and DudeCT on the IBM Z lane; BINSEC is not claimed today&lt;/li&gt;
&lt;li&gt;Linux &lt;code&gt;powerpc64le&lt;/code&gt;: artifact/provenance review, LLVM IR/ASM/object heuristics, and DudeCT on the IBM Power10 lane; BINSEC is not claimed today&lt;/li&gt;
&lt;li&gt;macOS &lt;code&gt;aarch64&lt;/code&gt;: local artifact/provenance review, LLVM IR/ASM/object heuristics, and DudeCT through &lt;code&gt;just ct-full&lt;/code&gt;; BINSEC is not claimed for Mach-O today&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WASM, &lt;code&gt;no_std&lt;/code&gt; bare-metal, Windows, Linux MUSL, macOS &lt;code&gt;x86_64&lt;/code&gt;, GCC codegen, and Cranelift are not part of the current native CT release claim. Some build today. Some have artifact-only or intended coverage. They still need their own evidence before I will claim constant-time behavior for them. I DO plan to add GCC and Cranelift coverage as time allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perf!
&lt;/h2&gt;

&lt;p&gt;Constant-time validation is not an excuse to be slow. In fact, it is motivation not to be.&lt;/p&gt;

&lt;p&gt;The current bench overview is generated from raw results (an LLM generates this document programmatically) and includes the losses next to the wins:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the 06/09/2026 v0.4.0 bench evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux, fastest-external: 3,958 wins out of 6,525 matched comparisons&lt;/li&gt;
&lt;li&gt;Linux, wins-or-ties: 5,878 out of 6,525 matched comparisons&lt;/li&gt;
&lt;li&gt;Linux, fastest-external geomean: 1.60x&lt;/li&gt;
&lt;li&gt;Apple Silicon, fastest-external: 373 wins out of 725 matched comparisons&lt;/li&gt;
&lt;li&gt;Apple Silicon, wins-or-ties: 693 out of 725 matched comparisons&lt;/li&gt;
&lt;li&gt;Apple Silicon, fastest-external geomean: 1.41x&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some category numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checksums: 2.52x Linux fastest-external geomean&lt;/li&gt;
&lt;li&gt;Hashes/MACs/XOFs: 1.41x&lt;/li&gt;
&lt;li&gt;Auth/KDF: 1.24x&lt;/li&gt;
&lt;li&gt;RSA: 1.55x&lt;/li&gt;
&lt;li&gt;AEAD: 1.56x&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fastest External = aws-lc-rs, ring, dryoc, dalek, crc-fast, RustCrypto, SHA2/3, Blake3, and others.&lt;/p&gt;

&lt;p&gt;And the weak spots are still public too: Linux scrypt/password hashing, Linux ChaCha20-Poly1305 rows against &lt;code&gt;ring&lt;/code&gt; and &lt;code&gt;aws-lc-rs&lt;/code&gt;, near-parity Ed25519/X25519 ops, RISC-V checksum point losses, and Apple Silicon SHA3/XXH3 plus localized BLAKE3/CRC rows.&lt;/p&gt;

&lt;p&gt;I will continue to push the envelope here. My current work relies on this crate being small, fast, and safe... that work is my life.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;rscrypto&lt;/code&gt; Is Today
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rscrypto&lt;/code&gt; is a pure-Rust primitive stack.&lt;/p&gt;

&lt;p&gt;It includes hashes, MACs, KDFs, password hashing, RSA, Ed25519, X25519, AEADs, CRCs, fast non-cryptographic hashes, &lt;code&gt;no_std&lt;/code&gt;, WASM builds, portable fallbacks, and hardware accel in one crate.&lt;/p&gt;

&lt;p&gt;Use one primitive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;rscrypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"sha2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or the full primitive stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;rscrypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"getrandom"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The primitive stack does not depend on OpenSSL, C FFI, RustCrypto, dalek, the &lt;code&gt;blake3&lt;/code&gt; crate, or the &lt;code&gt;crc-*&lt;/code&gt; crates. Optional integrations such as &lt;code&gt;getrandom&lt;/code&gt;, &lt;code&gt;serde&lt;/code&gt;, and &lt;code&gt;rayon&lt;/code&gt; are opt-in.&lt;/p&gt;

&lt;p&gt;In my own codebase, replacing the pile of primitive deps w/ &lt;code&gt;rscrypto&lt;/code&gt; removed fifteen dependencies and C-libs. It brought my compile times down drastically in conjunction w/ &lt;a href="https://github.com/loadingalias/cargo-rail" rel="noopener noreferrer"&gt;cargo-rail&lt;/a&gt; usage. That is not a universal promise, but it is the kind of consolidation this crate is designed to make possible: one feature matrix, one dispatch model, one security policy, one benchmark story. This is also my ethos as of late. I am not willing to play supply-chain roulette.&lt;/p&gt;

&lt;p&gt;Remember, this is not a protocol stack. It is not TLS, PKI, key management, or a FIPS module.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;The roadmap is focused on building trust for the time being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;broader algo coverage where the primitive belongs in this crate&lt;/li&gt;
&lt;li&gt;reviewed artifact hashes and artifact-diff review for CT-critical symbols&lt;/li&gt;
&lt;li&gt;more formal and semi-formal verification experiments&lt;/li&gt;
&lt;li&gt;third-party audit work before v1 is really important to me&lt;/li&gt;
&lt;li&gt;FIPS-ready structure w/o pretending to be FIPS validated&lt;/li&gt;
&lt;li&gt;better CT evidence for WASM and &lt;code&gt;no_std&lt;/code&gt;, w/ engine/hardware-specifics&lt;/li&gt;
&lt;li&gt;GCC and Cranelift CT backends after the LLVM evidence remains stable for a bit&lt;/li&gt;
&lt;li&gt;platform expansion where real hardware and evidence can back the claim&lt;/li&gt;
&lt;li&gt;post-quantum primitives only with portable constant-time baselines, official vectors, malformed-input tests, and benchmark coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rules will remain the same: If a feature cannot be validated, benched, documented, and maintained, it does not belong in the public library yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback Wanted
&lt;/h2&gt;

&lt;p&gt;If you are building systems where cryptographic correctness matters, or where performance of the primitives gives you a meaningful edge - I would like feedback on the approach, tooling, and validation methodology. &lt;/p&gt;

&lt;p&gt;Especially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the CT manifest shape&lt;/li&gt;
&lt;li&gt;the DudeCT case model&lt;/li&gt;
&lt;li&gt;the BINSEC kernel boundary&lt;/li&gt;
&lt;li&gt;the target/platform claims&lt;/li&gt;
&lt;li&gt;the benchmark methodology&lt;/li&gt;
&lt;li&gt;the API shape before v1&lt;/li&gt;
&lt;li&gt;migration blockers from RustCrypto, &lt;code&gt;blake3&lt;/code&gt;, &lt;code&gt;crc-fast&lt;/code&gt;, &lt;code&gt;crc32fast&lt;/code&gt;, &lt;code&gt;ring&lt;/code&gt;, &lt;code&gt;aws-lc-rs&lt;/code&gt;, or other primitive crates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/loadingalias/rscrypto" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Crates.io: &lt;a href="https://crates.io/crates/rscrypto" rel="noopener noreferrer"&gt;https://crates.io/crates/rscrypto&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs.rs: &lt;a href="https://docs.rs/rscrypto" rel="noopener noreferrer"&gt;https://docs.rs/rscrypto&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Constant-time policy: &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/docs/constant-time.md" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto/blob/main/docs/constant-time.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Security guidance: &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/docs/security.md" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto/blob/main/docs/security.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Benchmark overview: &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto/blob/main/benchmark_results/OVERVIEW.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Migration guides: &lt;a href="https://github.com/loadingalias/rscrypto/blob/main/docs/migration/README.md" rel="noopener noreferrer"&gt;https://github.com/loadingalias/rscrypto/blob/main/docs/migration/README.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Discussions, issues, benchmarks, and hard technical criticism are welcome. Do not be shy. I have thick skin.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cryptography</category>
      <category>cybersecurity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>cargo-rail: Making Rust Monorepos Boring Again</title>
      <dc:creator>loadingalias</dc:creator>
      <pubDate>Wed, 10 Dec 2025 07:10:09 +0000</pubDate>
      <link>https://dev.to/loadingalias/cargo-rail-making-rust-monorepos-boring-again-3i93</link>
      <guid>https://dev.to/loadingalias/cargo-rail-making-rust-monorepos-boring-again-3i93</guid>
      <description>&lt;p&gt;Rust monorepos are painful. Your dependency graph drifts, CI runs too much, and extracting crates for OSS means Copybara (Java) or git subtree hell.&lt;/p&gt;

&lt;p&gt;After 18 months of fighting these problems, I built &lt;strong&gt;cargo-rail&lt;/strong&gt; — 13 direct dependencies, four workflows, zero workspace-hack crates.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;justfile&lt;/code&gt; had grown to over 1k lines. I had thirty shell scripts just to run tests. I wanted to release a few crates to the OSS community but &lt;code&gt;git subtree&lt;/code&gt; was a project unto itself, and Copybara meant pulling in Java tooling. I searched for a solution to modern Rust monorepo challenges and couldn't find one that fit, so I built cargo-rail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cargo-rail is a single Cargo subcommand that unifies dependencies, plans and executes graph-aware CI, splits/syncs repositories, and automates releases for Rust workspaces — with a small dependency footprint.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: cargo-rail makes Rust monorepos lean, boring, and safe. It keeps your dependency graph clean, finds hidden workspace-feature bugs, runs checks only where changes matter, lets you split crates with full history, and automates releases.&lt;/p&gt;

&lt;p&gt;Quick start:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-rail
cargo rail init
cargo rail unify &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Quick links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/loadingalias/cargo-rail" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crates.io/crates/cargo-rail" rel="noopener noreferrer"&gt;Crates.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/loadingalias/cargo-rail-action" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Who This Is For
&lt;/h2&gt;

&lt;p&gt;This article is for you if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You maintain a Rust workspace with multiple crates (a monorepo or a "fat" workspace).&lt;/li&gt;
&lt;li&gt;Your CI is slow or expensive and you'd like to only run what actually changed.&lt;/li&gt;
&lt;li&gt;You care about dependency hygiene and supply-chain surface area.&lt;/li&gt;
&lt;li&gt;You want to stay on Cargo (not Bazel/Buck2/Moon) but still have a first-class monorepo story.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Four Problems
&lt;/h2&gt;

&lt;p&gt;Rust monorepos are hard because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build graphs get bloated and misaligned.&lt;/li&gt;
&lt;li&gt;CI slows down without graph-aware planning.&lt;/li&gt;
&lt;li&gt;Extracting OSS crates cleanly (with history) is painful.&lt;/li&gt;
&lt;li&gt;Release tooling is often heavy and expands your supply chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how cargo-rail approaches each of these.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Build Graph
&lt;/h3&gt;

&lt;p&gt;Rust is notorious for compilation times and large dependency graphs. I needed a way to keep my graph honest: unify versions against resolved metadata, prune dead features, drop unused deps, and compute MSRV from what I actually depend on.&lt;/p&gt;

&lt;p&gt;I also wanted to avoid the "workspace-hack crate" model from &lt;code&gt;cargo-hakari&lt;/code&gt;. I didn't want another synthetic crate, and I didn't want another maintenance lane in CI.&lt;/p&gt;

&lt;p&gt;While building this, I found a class of hidden bugs: undeclared features borrowed across workspace members. Cargo's workspace feature unification can mask these until isolated builds or publish-time. cargo-rail now detects and can auto-fix them.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Change Detection
&lt;/h3&gt;

&lt;p&gt;I'm a solo startup founder working on low-level systems code. I run lots of variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit tests, integration tests, and doc-tests.&lt;/li&gt;
&lt;li&gt;Property tests and concurrency tests via &lt;code&gt;loom&lt;/code&gt; and &lt;code&gt;shuttle&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Memory safety checks with &lt;code&gt;Miri&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mutation tests, fuzzing, and benchmarks via &lt;code&gt;Criterion&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Multiple sanitizer setups across targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every &lt;code&gt;just check&lt;/code&gt; was running &lt;code&gt;cargo fmt&lt;/code&gt;, &lt;code&gt;cargo check&lt;/code&gt;, &lt;code&gt;cargo clippy&lt;/code&gt;, &lt;code&gt;cargo doc&lt;/code&gt;, &lt;code&gt;cargo audit&lt;/code&gt;, and &lt;code&gt;cargo deny&lt;/code&gt; for far more code than needed.&lt;/p&gt;

&lt;p&gt;Without robust change planning, development velocity drops hard. I needed to run only what changed, deterministically, without a maze of custom scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Distribution
&lt;/h3&gt;

&lt;p&gt;The first crates I built were strong OSS candidates. I wanted to split them from a private/canonical monorepo into clean public repos with full history.&lt;/p&gt;

&lt;p&gt;That workflow is deceptively hard. I could script &lt;code&gt;git subtree&lt;/code&gt; forever and hope I didn't cut history wrong, or I could pull in Copybara. Neither was attractive.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Release, Publish, and Maintain
&lt;/h3&gt;

&lt;p&gt;Once I looked seriously at split/sync, release automation was the obvious next bottleneck.&lt;/p&gt;

&lt;p&gt;There are excellent tools in this space. But many pull in very large dependency graphs for comparatively straightforward tasks. I wanted a workflow with a smaller attack surface and fewer moving parts.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;cargo-rail is built on two things every Rust team already has: &lt;strong&gt;git&lt;/strong&gt; and &lt;strong&gt;Cargo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It uses system &lt;code&gt;git&lt;/code&gt;, Cargo metadata, and a deterministic planner contract to keep local and CI behavior aligned. No daemon, no background scheduler, no parallel ecosystem of scripts.&lt;/p&gt;

&lt;p&gt;At a high level, cargo-rail covers four workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unify&lt;/strong&gt; — keep your dependency graph clean, deduplicated, and honest about MSRV.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan / Run&lt;/strong&gt; — build a deterministic change plan, then execute only selected surfaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split / Sync&lt;/strong&gt; — extract crates with full git history and keep them in sync with the monorepo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release&lt;/strong&gt; — plan and publish dependency-order releases with a minimal toolchain.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-rail
&lt;span class="c"&gt;# or via cargo-binstall for prebuilt binaries&lt;/span&gt;
cargo binstall cargo-rail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why It's Different
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Single Cargo subcommand, no daemon, no external scheduler.&lt;/li&gt;
&lt;li&gt;Built on Cargo's resolved graph, not just manifest syntax or path filters.&lt;/li&gt;
&lt;li&gt;Uses your system &lt;code&gt;git&lt;/code&gt; directly; no &lt;code&gt;libgit2&lt;/code&gt; or &lt;code&gt;gitoxide&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Planner-first model (&lt;code&gt;plan&lt;/code&gt; + &lt;code&gt;run&lt;/code&gt;) keeps local and CI logic aligned.&lt;/li&gt;
&lt;li&gt;Direct dependency footprint is small (&lt;code&gt;Cargo.toml&lt;/code&gt; currently has 13 direct deps).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of this post walks through the four workflows in detail.&lt;/p&gt;




&lt;h2&gt;
  
  
  Workflow A: Dependency Unification — Optimize Your Dependency Graph
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Commands:&lt;/strong&gt; &lt;code&gt;cargo rail init&lt;/code&gt;, &lt;code&gt;cargo rail unify&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail init                    &lt;span class="c"&gt;# generates .config/rail.toml&lt;/span&gt;
cargo rail unify &lt;span class="nt"&gt;--check&lt;/span&gt;           &lt;span class="c"&gt;# preview changes (CI-safe, exits 1 if changes needed)&lt;/span&gt;
cargo rail unify                   &lt;span class="c"&gt;# apply changes (first apply creates an undo backup)&lt;/span&gt;
cargo rail config &lt;span class="nb"&gt;sync&lt;/span&gt;             &lt;span class="c"&gt;# refresh/add new config fields after upgrades&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What &lt;code&gt;unify&lt;/code&gt; does for each configured target triple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unifies versions&lt;/strong&gt; based on what Cargo actually resolved (no syntax parsing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detects/fixes undeclared features&lt;/strong&gt; that are only satisfied by workspace-wide feature unification.&lt;/li&gt;
&lt;li&gt;Computes MSRV via configurable policy (&lt;code&gt;deps&lt;/code&gt;, &lt;code&gt;workspace&lt;/code&gt;, or &lt;code&gt;max&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prunes dead features&lt;/strong&gt; that are never enabled (empty no-op features).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detects/removes unused deps&lt;/strong&gt; using graph + compiler diagnostics (&lt;code&gt;unused_crate_dependencies&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pins transitives&lt;/strong&gt; through a configurable host as a &lt;code&gt;cargo-hakari&lt;/code&gt; replacement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wire &lt;code&gt;cargo rail config sync&lt;/code&gt; into your post-upgrade flow. It preserves existing settings/comments while adding missing defaults.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This solved my first problem.&lt;/strong&gt; Build graphs in local and CI runs became leaner and easier to reason about.&lt;/p&gt;




&lt;h2&gt;
  
  
  Workflow B: Change Detection — Test Only What Changed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Commands:&lt;/strong&gt; &lt;code&gt;cargo rail plan&lt;/code&gt;, &lt;code&gt;cargo rail run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Originally I used path filters and shell scripts. It worked until it didn't.&lt;/p&gt;

&lt;p&gt;Now it's planner-first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail plan &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;--explain&lt;/span&gt;      &lt;span class="c"&gt;# show what changed and why&lt;/span&gt;
cargo rail plan &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; json        &lt;span class="c"&gt;# machine contract for CI&lt;/span&gt;
cargo rail plan &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; github      &lt;span class="c"&gt;# GitHub Actions outputs&lt;/span&gt;
cargo rail run &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; ci    &lt;span class="c"&gt;# execute planner-selected surfaces&lt;/span&gt;
cargo rail run &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--surface&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;         &lt;span class="c"&gt;# override and run full test surface&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The planner classifies changes into surfaces like &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;bench&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;, and &lt;code&gt;infra&lt;/code&gt;. Config lives in &lt;code&gt;[change-detection]&lt;/code&gt; and &lt;code&gt;[run]&lt;/code&gt; inside &lt;code&gt;rail.toml&lt;/code&gt;. &lt;code&gt;impact&lt;/code&gt; is diagnostic; &lt;code&gt;scope&lt;/code&gt; is the execution handoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Action
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/loadingalias/cargo-rail-action" rel="noopener noreferrer"&gt;&lt;code&gt;cargo-rail-action&lt;/code&gt;&lt;/a&gt; wraps planner output for CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ci&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;loadingalias/cargo-rail-action@v4&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rail&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run selected CI profile&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.rail.outputs.build == 'true' || steps.rail.outputs.test == 'true' || steps.rail.outputs.infra == 'true'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo rail run --since "${{ steps.rail.outputs.base-ref }}" --profile ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run docs pipeline&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.rail.outputs.docs == 'true'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo rail run --since "${{ steps.rail.outputs.base-ref }}" --surface docs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where I saw the biggest day-to-day velocity jump: fewer wasted runs, fewer custom scripts, clearer reasoning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Try it now:&lt;/strong&gt; &lt;code&gt;cargo install cargo-rail &amp;amp;&amp;amp; cargo rail init &amp;amp;&amp;amp; cargo rail plan --merge-base --explain&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Workflow C: Split &amp;amp; Sync — Split Crates and Sync Repos with Full History
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Commands:&lt;/strong&gt; &lt;code&gt;cargo rail split&lt;/code&gt;, &lt;code&gt;cargo rail sync&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is high-risk transformation work. If you get it wrong, you lose history or break developer flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail &lt;span class="nb"&gt;split &lt;/span&gt;init my-crate         &lt;span class="c"&gt;# add split config to rail.toml for one or many crates&lt;/span&gt;
cargo rail &lt;span class="nb"&gt;split &lt;/span&gt;run my-crate &lt;span class="nt"&gt;--check&lt;/span&gt;  &lt;span class="c"&gt;# preview split&lt;/span&gt;
cargo rail &lt;span class="nb"&gt;split &lt;/span&gt;run my-crate          &lt;span class="c"&gt;# execute split with git history&lt;/span&gt;
cargo rail &lt;span class="nb"&gt;sync &lt;/span&gt;my-crate               &lt;span class="c"&gt;# bidirectional sync w/ conflict strategy&lt;/span&gt;
cargo rail &lt;span class="nb"&gt;sync &lt;/span&gt;my-crate &lt;span class="nt"&gt;--to-remote&lt;/span&gt;   &lt;span class="c"&gt;# monorepo -&amp;gt; split repo&lt;/span&gt;
cargo rail &lt;span class="nb"&gt;sync &lt;/span&gt;my-crate &lt;span class="nt"&gt;--from-remote&lt;/span&gt; &lt;span class="c"&gt;# split repo -&amp;gt; monorepo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Design decision:&lt;/strong&gt; monorepo to split is treated as canonical-forward; split to monorepo is review-oriented. Conflict strategies include &lt;code&gt;manual&lt;/code&gt; (default), &lt;code&gt;ours&lt;/code&gt;, &lt;code&gt;theirs&lt;/code&gt;, and &lt;code&gt;union&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean extraction of crates with full git history.&lt;/li&gt;
&lt;li&gt;A way to open-source selected crates while keeping private work private.&lt;/li&gt;
&lt;li&gt;A path to collaborate in split repos and merge changes back safely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three effective modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single:&lt;/strong&gt; One crate -&amp;gt; new repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combined + standalone:&lt;/strong&gt; Multiple crates -&amp;gt; one repo, separate crates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combined + workspace:&lt;/strong&gt; Multiple crates -&amp;gt; extracted workspace layout&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Workflow D: Release — Automate Safe, Minimal Releases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Commands:&lt;/strong&gt; &lt;code&gt;cargo rail release&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail release init crate               &lt;span class="c"&gt;# define release config&lt;/span&gt;
cargo rail release check crate              &lt;span class="c"&gt;# fast validation&lt;/span&gt;
cargo rail release check crate &lt;span class="nt"&gt;--extended&lt;/span&gt;   &lt;span class="c"&gt;# publish dry-run + MSRV validation&lt;/span&gt;
cargo rail release run crate &lt;span class="nt"&gt;--check&lt;/span&gt;        &lt;span class="c"&gt;# preview release plan&lt;/span&gt;
cargo rail release run crate &lt;span class="nt"&gt;--bump&lt;/span&gt; minor   &lt;span class="c"&gt;# execute: version, changelog, tag, publish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Release computes publish order from the workspace dependency graph. Configuration lives in &lt;code&gt;rail.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[release]&lt;/span&gt;
&lt;span class="py"&gt;tag_prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v"&lt;/span&gt;
&lt;span class="py"&gt;tag_format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{crate}-{prefix}{version}"&lt;/span&gt;
&lt;span class="py"&gt;require_clean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;changelog_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CHANGELOG.md"&lt;/span&gt;
&lt;span class="py"&gt;push&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;create_github_release&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;require_release_notes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Version bump, changelog, tag, push, publish, and optional GitHub release can all run through one command surface. For an owned GitHub release, set both &lt;code&gt;push = true&lt;/code&gt; and &lt;code&gt;create_github_release = true&lt;/code&gt;; cargo-rail pushes the release commit and tag before publishing crates or making the GitHub Release public.&lt;/p&gt;

&lt;p&gt;I've also released &lt;code&gt;cargo-rail&lt;/code&gt; using &lt;code&gt;cargo-rail&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Minimal Attack Surface
&lt;/h2&gt;

&lt;p&gt;I care about supply-chain security. Monorepo orchestration should be aggressively simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cargo-rail currently has 13 direct dependencies in &lt;code&gt;Cargo.toml&lt;/code&gt;. On the current &lt;code&gt;v0.13.4&lt;/code&gt; lockfile, &lt;code&gt;cargo tree -e normal -p cargo-rail --locked&lt;/code&gt; resolves to 56 unique non-root crates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is still materially smaller than the "several separate tools with hundreds of deps" stack many teams end up with.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Validation
&lt;/h2&gt;

&lt;p&gt;I've tested across public Rust workspaces with real history and real CI constraints.&lt;/p&gt;

&lt;p&gt;Here are current &lt;code&gt;cargo rail unify&lt;/code&gt; results from validation forks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repository&lt;/th&gt;
&lt;th&gt;Crates&lt;/th&gt;
&lt;th&gt;Deps Unified&lt;/th&gt;
&lt;th&gt;Undeclared Features&lt;/th&gt;
&lt;th&gt;MSRV&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tokio&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;1.85.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;helix&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;1.87.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;meilisearch&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;70&lt;/td&gt;
&lt;td&gt;215&lt;/td&gt;
&lt;td&gt;1.88.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;helix-db&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;1.88.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Totals across 53 crates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;132 dependencies&lt;/strong&gt; unified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;258 undeclared features&lt;/strong&gt; fixed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 dead features&lt;/strong&gt; pruned&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Replaced
&lt;/h2&gt;

&lt;p&gt;In my own workspace, cargo-rail let me remove:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cargo-hakari&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail unify&lt;/code&gt; with &lt;code&gt;pin_transitives = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cargo-features-manager&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail unify&lt;/code&gt; with &lt;code&gt;prune_dead_features = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;cargo-udeps&lt;/code&gt;, &lt;code&gt;cargo-machete&lt;/code&gt;, &lt;code&gt;cargo-shear&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail unify&lt;/code&gt; with &lt;code&gt;detect_unused = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cargo-msrv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail unify&lt;/code&gt; with &lt;code&gt;msrv = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;dorny/paths-filter&lt;/code&gt; + 1k LoC shell&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail plan&lt;/code&gt; + &lt;code&gt;cargo rail run&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;release-plz&lt;/code&gt;, &lt;code&gt;cargo-release&lt;/code&gt;, &lt;code&gt;git-cliff&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cargo rail release&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Copybara / git-subtree&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cargo rail split&lt;/code&gt; + &lt;code&gt;cargo rail sync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change planning/execution&lt;/strong&gt; replaced most custom CI shell glue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI costs dropped materially&lt;/strong&gt; on my own workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;258 hidden feature issues&lt;/strong&gt; were surfaced and fixed across validation repos.&lt;/li&gt;
&lt;li&gt;Workflow is leaner and easier to reason about.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When Not to Use cargo-rail
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you're already on Bazel, Buck2, or Moon and you like that model, cargo-rail is not the right tool.&lt;/li&gt;
&lt;li&gt;If you have a single crate with simple CI, cargo-rail is more machinery than you need.&lt;/li&gt;
&lt;li&gt;If you want a general-purpose build system for a polyglot monorepo, cargo-rail is Rust-only and Cargo-native.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;cargo-rail fits when you have a Rust workspace and want to keep using Cargo while solving dependency hygiene, deterministic planning, split/sync, and release.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design Decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Multi-Target Resolution:&lt;/strong&gt; cargo-rail runs &lt;code&gt;cargo metadata --filter-platform&lt;/code&gt; per target and intersects results with guardrails. If it marks something unused, it is unused across configured targets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resolution-Based, Not Syntax-Based:&lt;/strong&gt; cargo-rail uses resolved Cargo metadata, not raw manifest guesswork.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System Git:&lt;/strong&gt; Uses your system &lt;code&gt;git&lt;/code&gt; directly. No &lt;code&gt;libgit2&lt;/code&gt;, no &lt;code&gt;gitoxide&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lossless TOML:&lt;/strong&gt; Uses &lt;code&gt;toml_edit&lt;/code&gt; to preserve comments/formatting in manifests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Planner Explainability:&lt;/strong&gt; &lt;code&gt;cargo rail plan --explain&lt;/code&gt;, &lt;code&gt;cargo rail graph&lt;/code&gt;, &lt;code&gt;cargo rail hash&lt;/code&gt;, &lt;code&gt;cargo rail diff-hash&lt;/code&gt;, and run receipts in &lt;code&gt;target/cargo-rail/receipts/&lt;/code&gt; make decisions auditable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;You don't need to restructure anything. Start small.&lt;/p&gt;

&lt;p&gt;If you only do one thing after reading this, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-rail

cargo rail init
cargo rail config validate

cargo rail unify &lt;span class="nt"&gt;--check&lt;/span&gt;    &lt;span class="c"&gt;# preview unification for your workspace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs in dry-run mode, creates no changes, and gives you a concrete "before vs after" for dependency hygiene.&lt;/p&gt;

&lt;p&gt;If it looks reasonable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail unify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to roll back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo rail unify undo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, when you're comfortable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# See what changed and why&lt;/span&gt;
cargo rail plan &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;--explain&lt;/span&gt;

&lt;span class="c"&gt;# Execute planner-selected test surface only&lt;/span&gt;
cargo rail run &lt;span class="nt"&gt;--merge-base&lt;/span&gt; &lt;span class="nt"&gt;--surface&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Migrating from cargo-hakari?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; migrate-to-rail
&lt;span class="c"&gt;# Remove workspace-hack crate and hakari.toml&lt;/span&gt;
cargo rail init
&lt;span class="c"&gt;# Edit rail.toml: set pin_transitives = true&lt;/span&gt;
cargo rail unify &lt;span class="nt"&gt;--check&lt;/span&gt;
cargo rail unify
cargo check &lt;span class="nt"&gt;--workspace&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cargo &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--workspace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full migration guide: &lt;a href="https://github.com/loadingalias/cargo-rail/blob/main/docs/migrate-hakari.md" rel="noopener noreferrer"&gt;docs/migrate-hakari.md&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;Short version: keep cargo-rail small, deterministic, and focused on Rust workspaces.&lt;/p&gt;

&lt;p&gt;Near-term:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stronger presets/examples for large public workspaces.&lt;/li&gt;
&lt;li&gt;Better custom-surface CI patterns and reporting.&lt;/li&gt;
&lt;li&gt;Sharper split/sync and release safety rails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Longer-term:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier integration with existing tooling (&lt;code&gt;nextest&lt;/code&gt;, &lt;code&gt;cargo-deny&lt;/code&gt;, custom pipelines).&lt;/li&gt;
&lt;li&gt;Keep planner contracts stable and continue tightening hash/diff-hash/graph explainability workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll keep the roadmap in the repo up to date; feedback and critiques are welcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it:&lt;/strong&gt; &lt;code&gt;cargo rail unify --check&lt;/code&gt; on your workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use it:&lt;/strong&gt; Wire &lt;code&gt;cargo-rail-action&lt;/code&gt; into CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Star it:&lt;/strong&gt; &lt;a href="https://github.com/loadingalias/cargo-rail" rel="noopener noreferrer"&gt;github.com/loadingalias/cargo-rail&lt;/a&gt; helps other teams find it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critique it:&lt;/strong&gt; If a design decision is wrong, open an issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you maintain a public Rust workspace and want a low-risk evaluation, I'm happy to open a small PR wiring in cargo-rail so you can see real impact before committing.&lt;/p&gt;

&lt;p&gt;What's your biggest Rust monorepo pain point?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/loadingalias/cargo-rail" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Star on GitHub&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/loadingalias/cargo-rail" rel="noopener noreferrer"&gt;cargo-rail&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Crates.io: &lt;a href="https://crates.io/crates/cargo-rail" rel="noopener noreferrer"&gt;cargo-rail&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Action: &lt;a href="https://github.com/loadingalias/cargo-rail-action" rel="noopener noreferrer"&gt;cargo-rail-action&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Migration Guide: &lt;a href="https://github.com/loadingalias/cargo-rail/blob/main/docs/migrate-hakari.md" rel="noopener noreferrer"&gt;migrate-hakari&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Change Detection Guide: &lt;a href="https://github.com/loadingalias/cargo-rail/blob/main/docs/change-detection.md" rel="noopener noreferrer"&gt;change-detection&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://github.com/loadingalias" rel="noopener noreferrer"&gt;@loadingalias&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cargo</category>
      <category>monorepo</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
