DEV Community

Cover image for An ofrenda for the Rust crates that went quiet
Lymah
Lymah Subscriber

Posted on AI-assisted

An ofrenda for the Rust crates that went quiet

Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine

Quiet is not a verdict. Every crate in this post was somebody's free work. But when a dependency stops moving, someone should notice, and say thank you, and check whether it is gone or just finished.

What I Built

// unsafe-libyaml 0.2.11
It sorted the wild blooms, seeking order in chaos.
unsafe-libyaml 0.2.11: libyaml transpiled to rust by c2rust. First released 2022-07-03, last released 2024-03-17 (2.6 years before this scan), after 17 releases. Its repository has been archived. The last commit on its main branch was on 2024-03-21. RustSec advisory RUSTSEC-2024-0449 (2024-03-25) marks it unmaintained: unsafe-libyaml is unmaintained.
Enter fullscreen mode Exit fullscreen mode

Ofrenda reads the Cargo.lock files you give it and finds the crates that went quiet. For each one it builds a small card for an ofrenda page: the facts about the crate, and one line of remembrance.

The division of labour is the whole idea:

  • Code writes every fact. Rust works out which crates count as quiet and fetches their history from crates.io, their repository state from GitHub, and any "unmaintained" advisory from RustSec. It writes the facts line itself.
  • A small local model writes one line. Gemma 3 4B, running through Ollama on my laptop CPU, adds a single italic epitaph. Rust checks it and rejects it if it contains a digit, a time or number word, a valuation like "useful", a status word like "archived", a name that isn't in the crate's own description, or a technical term the description doesn't use.

If the model fails three times, the card simply shows the facts. A card with no poem is better than a card with a lie.

I read the theme as "honour the past, accurately".

Demo

hmtl card row 1
html card row 2
html card row 3

Code

GitHub logo Lymah123 / ofrenda

A Rust CLI that finds the quiet crates in your Cargo.lock, writes every fact itself, and lets a local Gemma add one checked line of remembrance.

ofrenda

An offering for the Rust crates in your Cargo.lock that went quiet.

Rust does everything that has to be true. It reads your lockfiles, fetches each crate's release history (crates.io), its repository state (GitHub) and any RustSec "unmaintained" advisory, and writes a facts line for each flagged crate. A small local model (Gemma 3 4B through Ollama) adds one short epitaph per crate That epitaph is the only thing the model writes, and Rust rejects it if it contains a digit, a number or time word, a valuation ("useful"), a status word ("archived"), a name that is not in the crate's own name or description, or a technical term the description does not use. A rejected epitaph is asked for again with the reason (up to three tries, with a list of words other epitaphs already used); after that the entry shows only the facts.

The epitaphs are poetry…

How I Built It

  • Model: Gemma 3 4B (open weights), run locally through Ollama in WSL on CPU only, no GPU.
  • Language: Rust. The only dependencies are regex and serde_json; it calls curl for crates.io, GitHub and Ollama.
  • Data: I scanned the lockfiles of three public projects (statix, ripgrep and bat): 342 crates.io packages. RustSec's advisory database is the ground truth for "unmaintained".
  • AI assistant: Claude, ChatGPT, and Copilot helped with debugging and brainstorming. I ran everything, chose the data, read the output, and decided what to fix.

Is "no release for two years" a good test for a dead crate?

I compared two rules against RustSec's unmaintained advisory list, using data collected on 2026-10-30.

Rule Flagged RustSec matches Not marked unmaintained Precision Recall
No release for 2+ years 52 6 46 0.12 0.86
Quiet + dead repository 38 6 32 0.16 0.86

The one RustSec-flagged crate the date rule missed is bincode. Its story is below.

RustSec marks 7 of the 342 as unmaintained. The date rule finds 6 of them and is wrong about most of what it flags. Release dates can't tell asleep from dead.

The repository check showed it. 14 of the quiet crates have had a commit in the last two years: utf8parse was committed to on 2026-10-25, num-traits on 2026-07-07, core-foundation-sys on 2026-09-14. Those are asleep, or finished. Two more, bisync_macros and countme, have archived repositories and no advisory. A few, like difflib and content_inspector, haven't had a commit since 2018. Nobody filed an advisory for them, so they count as false positives, which means the 0.16 is a floor. RustSec is a good ground truth, not a complete one.

The failure diary

  1. My first version let Gemma write the facts, and "verified" meant less than I said. It wrote that unsafe-libyaml was "unmaintained as of March 17, 2024". That's the last-release date. The advisory is dated 2024-03-25. My checker only compared tokens, and "March" and "17" both existed somewhere in the facts. It also wrote "useful", "valuable" and "archived" for crates whose facts said none of that, and turned 5.8 and 8.8 years into "five" and "eight". So I moved every fact into code.
  2. The poetry invented what libraries do. For atty it wrote "It checks the path". The crate checks whether a stream is a terminal, and its description is circular, so the model made something up. For paste, a token-pasting macro, it wrote "a steady hand for parsing". The fix was a rule: a technical word is allowed only if the crate's description uses it. Of my last 10 first attempts, 8 were rejected, 6 of them for invented technical terms (command, structure, data, code).
  3. My rule against repetition was too strict. I rejected any line that reused a long word from another epitaph. The model kept reaching for "smoothed rough edges", got rejected, and swapped in another word it had already used. Only 4 of 10 entries got a poem. Giving it the list of words to avoid up front, and a third try, got 7 of 10.

The final run: 7 epitaphs accepted (5 after a retry), 3 cards with facts only.

Why Does Open Innovation Matter?

  • I could watch it fail, and build around exactly how. Pinned open weights and cached output let me replay a failure exactly, and a hosted model can change under you. That let me turn each failure into a check: invented technical terms, repeated imagery, bare numbers.
  • The ground truth is open too. RustSec, crates.io and GitHub are all public, so anyone can rerun this on their own lockfile and check my numbers. The thing being remembered is open source, and so is the evidence.
  • Honest limits: the model runs locally, but the facts need the network (crates.io and GitHub). I did not compare against a hosted model, which would probably write better and more varied lines. My claim is smaller: a 4B model can write a harmless, checked line, if you stop it from writing facts.

Limits

  • Three lockfiles, 342 crates. The precision numbers are against RustSec, which is incomplete.
  • Only GitHub repositories are checked. Five quiet crates are hosted on GitLab, so their state stayed unknown.
  • The checks stop invented facts and unsupported technical terms. They don't make the poetry good, and a line can still be wrong in imagery. The page itself says so.
  • The epitaphs are repetitive. They're a small model's best effort with its cliches removed.

The Spirit of It

The card that stopped me was bincode. My date rule said it was still releasing: the last release was 2025-12-16, under a year ago. RustSec’s advisory (RUSTSEC-2025-0141), dated the same day, says something else. The team ended development for good after a doxxing and harassment incident, and considers version 1.3.3 complete.

That isn’t neglect, and it isn’t abandonment. It’s a decision, made after what the advisory calls a doxxing and harassment incident. My code could count releases and read dates. It could not have told me that.

The poem on bincode’s card was written by a model that never saw any of this. That is the point of the checks, and also their limit: they stop the model from inventing facts, but they can’t give it understanding.

Thank you, bincode team, for the years of work and for 1.3.3.

To the people behind these crates: thank you for the work, and for what it gave the rest of us.

Prize Categories

Best Use of Gemma. Gemma 3 runs locally as the epitaph writer, and the checking layer exists because of how a 4B Gemma fails

Top comments (0)