Blue Ridge Ruby 2026 · gem-contribute

gem-contribute

Building what you cannot find

Chris Hagmann · Blue Ridge Ruby 2026

Blue Ridge Ruby 2026 · gem-contribute

I wanted to contribute back.

I never figured out where to start.

Blue Ridge Ruby 2026 · gem-contribute

A small problem

I volunteered to help with Hack Day tomorrow.


I needed a list of good Ruby projects to point people at.


That list didn't exist.


So I built one.

Blue Ridge Ruby 2026 · gem-contribute

What's out there

  • goodfirstissue.dev · opt-in registry · sparse
  • goodfirstissues.com · opt-in registry · sparse
  • github.com/topics/good-first-issue · opt-in topic · sparse
  • forgoodfirstissue.github.com · curated · narrow

These all rely on maintainer opt-in — and most maintainers never do.


The signal I needed was a different kind of opt-in: mine.

Blue Ridge Ruby 2026 · gem-contribute

bundle fund for time

bundle fund reads your Gemfile.lock to answer
"where should my dollars go?"


gem-contribute reads the same file to answer
"where should my hours go?"

Blue Ridge Ruby 2026 · gem-contribute

The insight was already on disk

$ bundle list | wc -l
     216

Your Gemfile.lock is already curated.

  • ~216 maintainers you've already bet on
  • The OSS code you have the most context on
  • A vote of confidence with versions attached

Start there, not on GitHub.

Blue Ridge Ruby 2026 · gem-contribute

So I built it

$ gem-contribute scan
Scanning Gemfile.lock (234 gems)...
234 gems · 230 on github.com · 1 on gitlab.com · 3 unknown source

Top contributable projects (by open `good first issue` count):
  sorbet-runtime    50  github.com/sorbet/sorbet
  rspec-openapi      5  github.com/exoego/rspec-openapi
  gem-contribute     4  github.com/cdhagmann/gem-contribute
  packwerk           4  github.com/Shopify/packwerk
  rubocop            4  github.com/rubocop/rubocop
  gitlab             3  github.com/NARKOZ/gitlab
  pundit             2  github.com/varvet/pundit
  ...
Blue Ridge Ruby 2026 · gem-contribute

Fix it

$ gem-contribute fix rubocop/14102
Forking rubocop/rubocop → cdhagmann/rubocop...
Cloning into ~/code/oss/rubocop/rubocop...
Forked, cloned, and branched.
  path:     ~/code/oss/rubocop/rubocop
  branch:   gem-contribute/issue-14102
  upstream: github.com/rubocop/rubocop
  fork:     github.com/cdhagmann/rubocop

Next: cd ~/code/oss/rubocop/rubocop && make your changes,
      then `gem-contribute submit`.
Blue Ridge Ruby 2026 · gem-contribute

Submit it

$ gem-contribute submit
Pushing gem-contribute/issue-14102 to origin...
Opened browser to:
  https://github.com/rubocop/rubocop/compare/cdhagmann:gem-contribute/issue-14102
  ?expand=1&title=Fix+%2314102%3A+Allow+Lint%2FVoid+...&body=Closes+%2314102.

Browser opens. PR is pre-filled. Review. Click Create.

Blue Ridge Ruby 2026 · gem-contribute

The pattern generalizes

The things you depend on
are the things you should give back to.

Once you see that, you start noticing it everywhere.

Blue Ridge Ruby 2026 · gem-contribute

Build for yourself first.

Help where you can.

The rest is bonus.

Blue Ridge Ruby 2026 · gem-contribute

Thanks

gem install gem-contribute
cdhagmann.com/gem-contribute


Find me at Hack Day tomorrow — I'll watch it work on your laptop.


AI-assisted; ADRs explain why.

Speaker note (~10s): Title slide. Smile, take a breath, let the room settle. "I'm Chris Hagmann. I want to talk about building tools that don't exist yet — using a small one I made this week as the example."

Speaker note (~15s): Hold the slide. Don't read it aloud — let them read it themselves. Then, quietly: "That's been me for years. I suspect it's been some of you." Beat. Move on. Make it personal, not a claim about the whole room.

Speaker note (~25s): "I volunteered yesterday to help with Hack Day tomorrow. When I said yes, I needed a list of good Ruby projects with approachable issues to point people at. That list didn't exist." Pause on "didn't exist." Then: "So I built one. And along the way I noticed something that I think generalizes." That's the bridge to the next slide.

Speaker note (~20s): "There ARE resources. Four of them, all fine, all sparse." Don't read the URLs. The point is the pattern, not the list. "They're sparse for the same reason: they need a maintainer to opt their project in. Most maintainers never do." Then the turn: "The signal I needed was a different kind of opt-in. Mine." Land on "mine."

Speaker note (~25s): "Bundler shipped this insight years ago. `bundle fund` reads your Gemfile.lock to answer one question: where should my dollars go? It's the right index for the question." Beat. "Same index, different question: where should my hours go?" Land hard on the slogan. This is the meme of the talk.

Speaker note (~20s): "Two hundred and sixteen gems in this project. Two hundred and sixteen maintainers I've already bet on. Two hundred and sixteen codebases I have at least a little context on." "That's already a curated list. I just had to use it."

Speaker note (~45s): Let them read the output for ~10s before talking. Then walk down the list: "Sorbet has fifty open good-first-issues. Fifty." "RSpec OpenAPI, five. Packwerk, four. Rubocop, four." Point at gem-contribute on row three. Smile. "And the tool itself, four. It found itself. We'll come back to that." That's the meta-joke; don't oversell it.

(Drill-in slide cut for time. Mention in patter: "You can list the issues for any of these.")

Speaker note (~40s): Pre-frame: "You pick an issue. One command does the rest." Read silence ~8s. Then narrate: "It forks the repo to your account. Clones the fork locally. Adds the upstream remote. Creates a branch named after the issue." Pause. "All the git ceremony, gone."

Speaker note (~35s): "You write the fix. You commit it. You run submit." Beat for the URL to render. "It pushes your branch. It opens the compare URL with the title, the body, and `Closes #14102` already filled in." Bottom-line it: "Browser opens. PR is pre-filled. Review. Click Create."

Speaker note (~20s): The bridge from demo to lesson. Slow down here. The tool is the example, not the lesson. "I'm doing this for gems. But the pattern works wherever you look. The things you depend on are the things you should give back to. Once you see that, you start noticing it everywhere." Pause. Move on.

Speaker note (~15s): The takeaway slide. Read it slowly, one beat per line. Don't editorialize. The audience should leave the room with this in their head — not the install command, not the gem name, this.

Speaker note (~10s): "Thanks. The gem installs today. I'll be at Hack Day tomorrow if you want to try it on your laptop. Find me." Don't run over. Step back from the mic.