LukeMathWalker/cargo-chef
A cargo-subcommand to speed up Rust Docker builds using Docker layer caching.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ⚠Concentrated ownership — top contributor handles 58% of recent commits
- ⚠Scorecard: default branch unprotected (0/10)
- ✓Last commit 4w ago
- ✓28+ active contributors
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/lukemathwalker/cargo-chef)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card
This card auto-renders when someone shares https://repopilot.app/r/lukemathwalker/cargo-chef on X, Slack, or LinkedIn.
Ask AI about lukemathwalker/cargo-chef
Grounded in the actual source code. Pick a starter question or write your own.
Onboarding doc
Onboarding: LukeMathWalker/cargo-chef
Generated by RepoPilot · 2026-06-24 · Source
🎯Verdict
GO — Healthy across the board
- Last commit 4w ago
- 28+ active contributors
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 58% of recent commits
- ⚠ Scorecard: default branch unprotected (0/10)
<sub>Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests, cross-checked against OpenSSF Scorecard</sub>
⚡TL;DR
cargo-chef is a Rust cargo subcommand that generates a minimal project skeleton (containing only Cargo.toml and Cargo.lock files) to enable Docker layer caching of Rust dependencies independently from source code changes. It splits Rust Docker builds into two phases: cargo chef prepare generates a recipe.json containing the dependency graph structure, and cargo chef cook rebuilds dependencies from that recipe, allowing Docker to cache the expensive compilation layer even when source code changes. Single-crate binary+library structure: src/lib.rs exports the chef library, src/main.rs defines the CLI using clap derive macros. Core logic splits into src/recipe.rs (recipe generation) and src/skeleton/ (minimal project reconstruction with version masking and target handling). Tests are integration-focused: tests/caching/ validates end-to-end Docker layer behavior, tests/skeletons/ validates skeleton generation for workspaces and toolchains.
👥Who it's for
Rust backend developers and DevOps engineers building containerized Rust applications who want faster Docker image builds by leveraging layer caching. Specifically, those deploying web services and microservices who follow multi-stage Docker patterns and experience slow builds when dependencies change.
🌱Maturity & risk
Production-ready and actively maintained. The project has CI/CD pipelines (see .github/workflows/), comprehensive test suites (tests/caching/ and tests/skeletons/), semantic versioning with release automation (release-plz), and a clear CHANGELOG.md. The v0.1.77 version and presence of audit workflows indicate stable, security-conscious maintenance.
Low risk overall. The dependency surface is controlled (clap, serde, cargo-manifest, guppy—all mainstream crates). Single-maintainer risk exists (LukeMathWalker as primary author), but the project is published on crates.io with CI gating on general.yml and release.yml. No obvious breaking changes visible; the two-command design is simple and unlikely to change drastically. Main risk: dependency on cargo-manifest v0.21.0 and guppy v0.17—monitor these for security patches.
Active areas of work
No specific recent changes visible in file list, but release.yml and tag-and-publish.yml indicate automated release pipelines. The .release-plz.toml file suggests use of release-plz for semantic versioning automation. Dependabot is configured (.github/dependabot.yml) for keeping dependencies up-to-date. The project appears in maintenance mode: stable, security-audited (audit-on-push.yml, scheduled-audit.yml), but not undergoing major feature development.
🚀Get running
git clone https://github.com/LukeMathWalker/cargo-chef.git
cd cargo-chef
cargo build
cargo test
To use locally (though not recommended per README): cargo install cargo-chef --locked
Daily commands:
cargo run -- prepare --recipe-path recipe.json
cargo run -- cook --recipe-path recipe.json
For release mode: cargo run --release -- cook --recipe-path recipe.json. The intended usage is within Docker build stages, not local development.
🗺️Map of the codebase
src/main.rs— Entry point for the cargo-chef CLI; handles command routing and argument parsing via clap.src/lib.rs— Core library exposing public API for recipe generation and skeleton operations used by main and tests.src/recipe.rs— Defines Recipe struct and logic for parsing Cargo manifests and extracting dependency information for caching.src/skeleton/mod.rs— Main skeleton module coordinating dependency tree extraction and serialization for Docker layer optimization.src/skeleton/read.rs— Reads and parses Cargo.lock and Cargo.toml files to build the dependency skeleton structure.Cargo.toml— Project manifest defining dependencies (clap, serde, log) and binary/library targets; version 0.1.77.docker/Dockerfile— Example multi-stage Docker build demonstrating cargo-chef workflow for optimal layer caching.
🧩Components & responsibilities
- Recipe Generator (serde_json, glob patterns) — Parses Cargo manifests and produces deterministic JSON recipe for Docker caching
- Failure mode: Malformed Cargo.toml causes deserialization error; user must fix manifest
- Skeleton Extractor (toml parsing, version_masking module) — Builds dependency tree from Cargo.lock; filters by target and applies version normalization
- Failure mode: Missing or out-of-sync Cargo.lock; skeleton may be incomplete or stale
- CLI Router (clap, env_logger) — Routes prepare/cook subcommands and manages logging output
- Failure mode: Invalid subcommand or missing recipe file; user error with clear error message
- Docker Integration (Docker COPY, RUN, layer caching) — Multi-stage Dockerfile copies recipe and runs cargo chef cook in isolated layer
- Failure mode: Recipe out of date relative to source; cook rebuilds unnecessarily or fails
🔀Data flow
Cargo.toml + Cargo.lock→Recipe struct— Manifest parsing extracts package metadata and dependency graphRecipe struct→recipe.json (Docker layer)— Serialization outputs deterministic skeleton for Docker COPYrecipe.json→cargo build (cook phase)— Docker layer cache hit avoids re-parsing manifests; cargo fetch/build from recipeCargo source (src/)→Docker runtime layer— Application code copied after dependencies; only recompiled if source or recipe changes
🛠️How to make changes
Add a new skeleton export format
- Define new format struct implementing serialization in src/skeleton/mod.rs (
src/skeleton/mod.rs) - Add format option to CLI enum in src/main.rs (
src/main.rs) - Add integration test validating new format output in tests/skeletons/tests/core.rs (
tests/skeletons/tests/core.rs)
Support additional Cargo manifest fields
- Extend Recipe struct and parsing logic in src/recipe.rs (
src/recipe.rs) - Update skeleton extraction in src/skeleton/read.rs to handle new fields (
src/skeleton/read.rs) - Add test case in tests/recipe.rs covering new manifest field (
tests/recipe.rs)
Add workspace-level dependency optimization
- Extend target filtering logic in src/skeleton/target.rs (
src/skeleton/target.rs) - Add workspace test case in tests/skeletons/tests/workspace.rs (
tests/skeletons/tests/workspace.rs) - Document workspace behavior in docker/README.md (
docker/README.md)
🔧Why these technologies
- clap 4 — Ergonomic CLI parsing with derive macros; integrates with cargo ecosystem via cargo feature
- serde/serde_json — Serializes recipe and skeleton to JSON for Docker portability; language-agnostic format
- env_logger — Structured logging for debugging manifest parsing and skeleton extraction; follows Rust conventions
⚖️Trade-offs already made
-
JSON recipe format vs. binary serialization
- Why: Human-readable output enables inspection and debugging; simpler Docker integration
- Consequence: Slightly larger artifact size; no performance cost in typical Docker workflows
-
Version masking in skeleton extraction
- Why: Prevents cache invalidation on patch version bumps (e.g., 1.0.0 → 1.0.1)
- Consequence: May mask genuine breaking changes in transitive dependencies; requires explicit updates
-
Two-phase cook workflow (prepare + cook)
- Why: Separates manifest parsing from dependency compilation; enables Docker layer reuse
- Consequence: Requires users to invoke tool twice; recipe staleness requires manual verification
🚫Non-goals (don't propose these)
- Real-time dependency updates or live workspace monitoring
- Cross-platform reproducibility guarantees (subject to Rust toolchain version)
- Optimization for monorepos with circular dependencies
- Support for non-Cargo build systems or alternative Rust package managers
⚠️Anti-patterns to avoid
- Recipe staleness risk (Medium) —
src/recipe.rs, docker/Dockerfile: Prepare phase is decoupled from cook; recipe.json may not match current Cargo.lock if manifests updated between phases - Version masking hides transitive semver breaks (Low) —
src/skeleton/version_masking.rs: Normalization strips patch versions; benign patch bump in transitive dep could introduce breaking change undetected - Implicit target filtering assumptions (Medium) —
src/skeleton/target.rs: Default target handling may skip optional dependencies; users unaware of what is/isn't cached without explicit inspection
🔥Performance hotspots
src/skeleton/read.rs(I/O + parsing latency) — Cargo.lock parsing is linear scan; large monorepos with thousands of transitive dependencies could exhibit O(n) latencysrc/recipe.rs(undefined) — No incre
🪤Traps & gotchas
- Never run locally on existing codebases: The README explicitly warns that prepare+cook will overwrite files. It is design-locked for Docker build contexts only. 2. Recipe.json is the single source of truth: Changes to Cargo.toml after prepare are ignored during cook—the recipe captures dependency state at prepare time. 3. Workspace handling is implicit: The code uses cargo-manifest and guppy to discover workspace members; non-standard workspace layouts may not be detected. 4. Version masking is fragile: The toolchain override in version_masking.rs rewrites Cargo.toml fields; if rustup channel syntax changes, this breaks silently.
🏗️Architecture
💡Concepts to learn
- Docker layer caching and cache invalidation — The entire purpose of cargo-chef is to exploit Docker's layer-by-layer caching; knowing why modifying source breaks the cache but modifying Cargo.lock doesn't (after prepare) is the core insight
- Cargo workspace and manifest resolution — cargo-chef must correctly identify all Cargo.toml files and their relationships in a workspace; the guppy/cargo-manifest dependency graph is non-trivial for monorepos
- Minimal reproducible builds (recipe extraction) — The core algorithm extracts the minimal set of files needed to build dependencies; this requires understanding which Cargo.toml metadata is essential vs. discardable
- Toolchain version pinning and rustup — version_masking.rs rewrites rust-toolchain specifications; understanding how rustup resolves channel/version strings is needed to debug toolchain override failures
- JSON serialization for intermediate representations (recipe as IR) — recipe.json acts as an intermediate representation passed between prepare and cook phases; understanding serde serialization and schema stability is important for backward compatibility
- Multi-stage Docker builds — cargo-chef is designed to be used in multi-stage Dockerfiles; knowing how to structure stages so dependencies build in one layer and source in another is the practical application
🔗Related repos
rust-lang/cargo— The official Cargo implementation that cargo-chef wraps; understanding Cargo's manifest parsing and metadata format is essentialclap-rs/clap— The CLI framework used by cargo-chef; if you need to extend argument parsing or add new subcommands, you'll reference clap's derive macro patternsguppy-rs/guppy— The dependency graph analysis library cargo-chef uses for resolving workspace members and dependency treessfackler/cargo-metadata— Alternative dependency metadata extraction used by other Rust tools; useful for understanding how cargo-manifest and guppy comparemoby/moby— Docker itself; understanding layer caching invalidation semantics is critical to why cargo-chef's two-phase approach works
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for workspace dependency handling in src/skeleton/mod.rs
The repo has skeleton tests (tests/skeletons/) but lacks specific integration tests validating the interaction between workspace manifests and the skeleton generation logic. The tests/skeletons/tests/workspace.rs file exists but is likely incomplete given the complexity of workspace handling in src/skeleton/mod.rs. This would catch regressions when users have complex workspace structures with interdependent crates.
- [ ] Review existing tests/skeletons/tests/workspace.rs to identify coverage gaps
- [ ] Add tests for workspace members with different dependency versions
- [ ] Add tests for workspace members with path dependencies pointing to other workspace crates
- [ ] Add tests for workspaces with optional workspace dependencies (MSRV consideration)
- [ ] Add tests validating that version_masking.rs correctly handles workspace member versions
- [ ] Run coverage.sh to verify new tests improve coverage of src/skeleton/
Add GitHub Actions workflow for cargo-chef binary distribution testing across multiple Rust versions
The repo has release.yml and docker.yml workflows, but lacks a dedicated MSRV (Minimum Supported Rust Version) validation workflow. Given that cargo-chef is a tool consumed by other projects' Docker builds, testing against multiple Rust versions (MSRV, stable, nightly) in CI would prevent silent breakages. The edition = "2018" constraint suggests MSRV compatibility is important.
- [ ] Create .github/workflows/msrv.yml that tests against Rust 1.56+ (or identify actual MSRV from Cargo.lock)
- [ ] Test with stable and nightly channels
- [ ] Include cargo check, cargo test, and cargo build --release steps
- [ ] Add matrix strategy for linux and macos targets
- [ ] Validate that dist-workspace.toml builds successfully across versions
Add property-based tests for recipe parsing and version masking in src/skeleton/version_masking.rs
The version_masking.rs module handles critical logic for cache invalidation by masking dependency versions. Currently, tests/skeletons/tests/masking.rs likely has example-based tests. Property-based testing (using proptest or quickcheck) would ensure masking behavior is correct across arbitrary Cargo.lock versions and semver patterns, reducing the risk of cache-correctness bugs.
- [ ] Review tests/skeletons/tests/masking.rs to identify what property invariants should hold
- [ ] Add proptest dependency to [dev-dependencies] in Cargo.toml
- [ ] Create property tests that generate arbitrary valid Cargo.lock entries and verify masking is idempotent
- [ ] Add property tests for semver version comparisons used in masking logic
- [ ] Validate that masked recipes remain valid JSON parseable by src/recipe.rs
- [ ] Ensure property tests catch edge cases like pre-release versions and build metadata
🌿Good first issues
- Add comprehensive tests for
src/skeleton/version_masking.rsintests/skeletons/tests/masking.rs—currently no coverage visible for edge cases like malformed toolchain strings or MSRV pins - Document the Recipe JSON schema in docs or comments: add docstring examples to src/recipe.rs struct fields showing concrete JSON output for single-crate and workspace projects
- Add error recovery tests in tests/caching/tests.rs for malformed Cargo.lock scenarios (corrupted TOML, missing [package] sections) to validate the anyhow error chain is user-friendly
⭐Top contributors
Click to expand
Top contributors
- @LukeMathWalker — 58 commits
- @dependabot[bot] — 5 commits
- @mladedav — 4 commits
- @Kobzol — 3 commits
- @krijoh92 — 2 commits
📝Recent commits
Click to expand
Recent commits
f044b77— feat: toml v1.1 support (SrGaabriel)8432876— chore: add OCI annotations (emersion)52669eb— chore: release v0.1.77 (LukeMathWalker)edba503— fix: Remove lints from manifests in recipe.json (LukeMathWalker)87e1a07— Mention preiter93 in the CHANGELOG for recipe minimization (LukeMathWalker)e13c7b7— chore: release v0.1.76 (LukeMathWalker)ad4e29e— chore: Upgrade to latest versions of dependencies (LukeMathWalker)f5ec502— chore: Use HashSet rather than Vec for contains check (LukeMathWalker)74e5740— perf: Use 'cargo metadata --no-deps' when prepare wasn't given a --bin option (LukeMathWalker)eaf2e72— feat: Minimize recipe to increase cache hit ratio (LukeMathWalker)
🔒Security observations
The cargo-chef project demonstrates reasonably good security practices with automated audit workflows and careful dependency management. The codebase is a build optimization tool with no obvious injection vectors (no SQL, no web rendering, no user input deserialization risks visible). Main concerns are: (1) ensuring dependency audits run with strict failure conditions, (2) confirming audit workflows are properly configured, (3) adding a security policy for vulnerability disclosure, and (4) verifying Docker image security scanning. No hardcoded secrets or credentials were identified in the visible file structure. The project would benefit from explicit security documentation and confirmed CI/CD security scanning automation.
- Medium · Outdated Dependencies with Known Vulnerabilities —
Cargo.toml - [dependencies] section. The project uses several dependencies that may have known vulnerabilities. Specifically, serde_json 1.0.149, clap 4, and guppy 0.17 should be evaluated against current security advisories. The Cargo.lock file should be checked against the RustSec advisory database. Fix: Run 'cargo audit' regularly in CI/CD pipelines. Update dependencies to the latest versions and monitor for security advisories using tools like cargo-deny or cargo-audit. - Low · Missing Security Audit CI Workflow Configuration —
.github/workflows/audit-on-push.yml and scheduled-audit.yml. While audit-on-push.yml and scheduled-audit.yml workflows exist, the configuration details are not visible. Without confirming these workflows run 'cargo audit' with fail-on-warnings settings, there's a risk of undetected vulnerabilities. Fix: Ensure audit workflows are configured to fail on any detected vulnerabilities. Confirm they run on every push and on a regular schedule. Use 'cargo audit' with appropriate flags and consider cargo-deny for additional policy enforcement. - Low · Permissive File Exclusion in Package —
Cargo.toml - exclude field. The Cargo.toml excludes 'tests' from the published package, but test files may contain sensitive information or examples that could leak details about the application's internal structure. Fix: Review test files to ensure they don't contain hardcoded credentials, API keys, or sensitive configuration examples. Consider using a more explicit exclusion pattern if needed. - Low · No Explicit Security Policy Document —
Repository root. The repository structure does not show a SECURITY.md or vulnerability disclosure policy, making it unclear how security issues should be reported. Fix: Create a SECURITY.md file documenting how to responsibly disclose security vulnerabilities to maintainers. This should include a non-public reporting mechanism. - Low · Docker Image Build without Security Scanning —
.github/workflows/docker.yml and docker/Dockerfile. The docker.yml workflow is present but its content is not visible. Docker images should be scanned for vulnerabilities during the build process. Fix: Integrate Docker image scanning tools (e.g., Trivy, Snyk, or similar) into the docker.yml workflow. Use minimal base images and apply security best practices in the Dockerfile.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/LukeMathWalker/cargo-chef shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live LukeMathWalker/cargo-chef
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/LukeMathWalker/cargo-chef.
What it runs against: a local clone of LukeMathWalker/cargo-chef — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in LukeMathWalker/cargo-chef | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 58 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of LukeMathWalker/cargo-chef. If you don't
# have one yet, run these first:
#
# git clone https://github.com/LukeMathWalker/cargo-chef.git
# cd cargo-chef
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of LukeMathWalker/cargo-chef and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "LukeMathWalker/cargo-chef(\\.git)?\\b" \\
&& ok "origin remote is LukeMathWalker/cargo-chef" \\
|| miss "origin remote is not LukeMathWalker/cargo-chef (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/main.rs" \\
&& ok "src/main.rs" \\
|| miss "missing critical file: src/main.rs"
test -f "src/lib.rs" \\
&& ok "src/lib.rs" \\
|| miss "missing critical file: src/lib.rs"
test -f "src/recipe.rs" \\
&& ok "src/recipe.rs" \\
|| miss "missing critical file: src/recipe.rs"
test -f "src/skeleton/mod.rs" \\
&& ok "src/skeleton/mod.rs" \\
|| miss "missing critical file: src/skeleton/mod.rs"
test -f "src/skeleton/read.rs" \\
&& ok "src/skeleton/read.rs" \\
|| miss "missing critical file: src/skeleton/read.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 58 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~28d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/LukeMathWalker/cargo-chef"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.
Embed this chat in your README →
Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.
<iframe src="https://repopilot.app/embed/lukemathwalker/cargo-chef" width="100%" height="500" style="border:1px solid #d0d7de; border-radius:8px;" allow="microphone" loading="lazy" ></iframe>