Rust

1. What's in the catalogue

One published line, 1.98.0, as two images — rustc and cargo — from catalogue 2026.35.22 (2026-08-25):

ToolCapsRequiresNotes
rustcrwbinutils, ccthe compiler; rustdoc ships in the same image
cargonet, rwbuilds and tests; ~/.cargo/registry is host-backed

Both are published with rw at the index level — a build tool inherently produces output. (The cargo-rust-simple example predates that decision: its transcripts show --cap rw typed by hand, when cargo carried no index-level capability. On the current catalogue the flag is not needed.) Nothing declared-not-published here — no rustup, no clippy, no rustfmt are in the catalogue.

2. The five-minute version

kapsl rustc --version
rustc 1.98.0 (88d9e12ae 2026-08-18)

kapsl cargo --version
cargo 1.98.0

Build and run a scratch project (Cargo.toml + src/main.rs):

kapsl cargo build
   Compiling hello v0.1.0 (/kapsl/workdir)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.58s

kapsl cargo run
     Running `target/debug/hello`
Hello from Rust!

No flags: rw from the index, and a stdlib-only project fetches nothing, so no net is exercised either. A project with crates.io dependencies needs net for the first build (or a capabilities: [net] line in the project overlay); after that, the index declares a host-backed ~/.cargo/registry cache, so already-fetched crates are reused across builds — even across different projects.

3. The environment story: a measured ABI pin

Rust is a compiled language, and compiled languages have a problem interpreted ones don't: the binary you build has to run against a C library floor. The catalogue pins that floor per image with an [image.abi] section, and the rule is that the pin is measured, never declared: the index build measures the actual GLIBC/glibc requirements of the binaries in the image and records what they need, rather than trusting a manifest to say what they need. A declared pin can lie; a measured one cannot.

What a C extension needs, concretely: a compiler and binutils reachable by name. That is why rustc's index entry declares req = binutils, cc — the gcc and binutils images are composed into its container, so build.rs scripts that shell out to cc and link libc work without the project declaring anything. A crate that builds a C dependency (the common case: anything with a build.rs) gets that floor for free.

4. Tooling

No rustfmt or clippy in the catalogue. kapsl cargo fmt works only if the rustfmt component is in the image; the published 1.98.0 line's examples don't use it, so don't write CI against it until the component ships. The one tooling affordance the catalogue does carry for cargo is per-subcommand credential handling: the published entry mounts ~/.cargo/credentials.toml and passes CARGO_REGISTRY_TOKEN for the publish/yank/logout subcommands — visible in kapsl --info cargo.

The IDE use case covers editor integration; rust-analyzer talking to a workspace is the same pattern as the other languages — the workspace is mounted, the tool runs in its own image.

5. Project patterns

  • cargo-rust-simple — all three levels of integration, subcommand_index: 2 (the program's serve subcommand sits after run --), port 8090 published only for the serve path, the rustup-shim caveat, and the built-binary limitation below with its failing transcripts.
  • cargo-project-config — the same shape as a pure project-config exercise, with a RUST_LOG transcript proving the overlay grant reaches the real container invocation.

The overlay from cargo-rust-simple is the clearest demonstration of subcommand_index doing real work — the trust review even prints which index each line uses:

tools:
  cargo:
    capabilities: [rw]
    subcommand_index: 2
    subcommands:
      serve:
        ports: ["8090"]
        args: ["--addr", "0.0.0.0:8090"]
  SECURITY  .kapslrc declares a project overlay
            cargo: +rw, port(serve@arg2) 8090, args(serve@arg2) --addr 0.0.0.0:8090
  INPUT     Apply this project's overlay?
            [ y ] yes    [ n ] no    [ o ] once

kapsl cargo run -- serve publishes 8090; kapsl cargo build and kapsl cargo test get no port. A test suite has no business holding a published port.

6. Known limitations

  • The built binary doesn't run standalone, yet. kapsl ./target/debug/hello validates the ELF and runs it against the minimal static base — and currently fails:

    kapsl ./target/debug/hello
    ./target/debug/hello: error while loading shared libraries: libgcc_s.so.1:
    cannot open shared object file: No such file or directory

    The cargo image is Ubuntu/glibc and does not set +crt-static, so default builds are dynamically linked; the static base ships libc6 and libm but no libgcc. The obvious workaround — static linking — also does not work today, because the toolchain has no static gcc_eh. The example carries both failing transcripts.

  • rustup collisions. ~/.local/bin/cargo is very likely already a rustup shim; kapsl --install cargo removes and replaces it, and rustup will not know that happened. If you use rustup for anything, prefer the project-overlay level, or shim a project-scoped alias name instead of cargo itself.

  • No formatter in the catalogue. rustfmt/clippy are not published; don't write CI against kapsl cargo fmt until they are.