Ever wondered how to build those interactive product tours that spotlight elements and walk users through your app? Ever wondered how you could with just roughly 100 lines of JS and modern CSS? Wonder now more, I will show and it will look like this:

Yes, just around 100 LoC 🤯
I built one using CSS Anchor Positioning and a Stimulus controller. The approach uses two techniques worth talking about: a clip-path spotlight effect (useful in all sorts of contexts) and CSS anchor positioning for the dialog (still very new as of mid-2026).
The full code, as always, is on GitHub.
The clip-path trick
The overlay covers the viewport with a semi-transparent background. But instead of sitting on top…
The Hidden Life of a UPI ID
A Bag of Bolts
So, a few weeks ago, I went to the hardware store to buy some casters and the hardware to mount them to a couple of cabinets. To save a few bucks, I decided to buy the hardware from the bulk bins. But, as I began filling my bag, I quickly noticed that not every bolt in the bin was the same size. Most of the bolts matched the label. But, some had clearly been misplaced.
Having experienced what it is like to make 2 or 3 trips to the hardware store to finish a project, I decided to pad my quantities by 10%, to mitigate the risk that I would need to…
ArchSpec 1.0: Executable Architecture Specification for Ruby’s Agentic Coding Era
More and more code is written by a model. Tests still tell you it works. RuboCop still tells you it’s tidy. Nothing tells you it still follows your architecture.
I released ArchSpec 1.0 today. It’s an architecture linter for Ruby and Rails. You declare your components and boundaries in one file, and every change gets checked, whether a person or an agent wrote it.
This is part of my push towards making Ruby one of the best languages to build with AI. RubyLLM is one piece. Schematist is another. Making the default Rails job queue fiber-based is another.
People and AIs take shortcuts
An agent or a person that’s in a hurry or doesn’t fully understand your architecture takes shortcuts.
The…
4.0.19 Released
RubyGems 4.0.19 includes enhancements, bug fixes and documentation and Bundler 4.0.19 includes enhancements, bug fixes and documentation.
To update to the latest RubyGems you can run:
gem update --system [--pre]
To update to the latest Bundler you can run:
gem install bundler [--pre]
bundle update --bundler=4.0.19
RubyGems Release Notes
Enhancements:
- Reject SafeMarshal collection lengths longer than the remaining input. Pull request #9756 by hsbt
- Installs bundler 4.0.19 as a default gem.
Bug fixes:
- Fix gem uninstall –user-install crash when GEM_HOME does not exist. Pull request #9749 by hsbt
Documentation:
- Document SPDX license handling for license= and licenses=.…
CVE-2026-55107 (kobako): kobako Sandbox Escape - guest eval reaches host RCE via method_missing → public_send (any bound Service)
_why day
Some parts of the book went way over my head, but I read it and re-read it. I wrote my first Shoes app, my first camping app1. This led me to attend my first conference and user group, my first Chaos Communication Congress, join my first open-source project, start my first podcast, and organize my own CoderDojo. I made friends for life through all of that. And _why‘s whimsical book lit that fire2. That‘s why I have a quote from him on my about page that I try to follow and sometimes do.
Today is _why day. „On 19 August 2009, _why’s accounts on Twitter and GitHub and his personally maintained websites went offline.“. Someone doxxed the person behind the artistic figure, so the artistic…
Halunke
In 2018, I invented and…
Git Rerere: Resolve That Conflict Once
In my previous post, AI Assistant for Our Blog Writing Process, I introduced the assistant we built to help with our blog writing. It has two pieces: an MCP (Model Context Protocol) server that holds the source of truth for our two blogs, and a Claude Code plugin that turns that information into workflows for suggesting topics, planning a post, drafting it and reviewing it.
That post was about deciding what to build. This one is about building it. We’ll go through the ingestion pipeline that gets our posts into a database, the embeddings that make the corpus searchable by meaning, the MCP server that exposes all of it, and the plugin that packages the workflows on top.
The stack
The…

Rails boot time is a DX metric in the AI age: meet require-profiler, learn to actually read sampling profilers, and see the pit stop that cut a 200-component monolith's boot by 40%.
Every Rails app race starts the same: load code, read config, then the green flag. But the bigger the app, the more startup drags on deploys, CI, and developer patience. This is doubly so as AI agents boot your app far more often than humans do. Thus, meet require-profiler, a new one-stop profiler for Ruby's code loading process! Grab it first when optimizing…
Power in numbers, and Pat Allan
Welcome to week two of our 2026 sponsorship drive!
Progress from week one
We’ve had a great response since we kicked things off last week: we’ve had ten new individuals join as sponsors! If everyone sticks around for a year (we’ll make it worthwhile, I promise!), that will amount to a full $2,400 towards our goal.
Thank you to our new supporters for proving there’s power in numbers!
We’d love to see more individuals get behind us, and if we can find 2-3 new businesses to join as supporters, we’ll get very close to being able to offer a first-time honorarium to our active maintainers. Learn more here.
Q&A with Pat
As a little treat this year, we’re bringing you Q&As from leading Hanakai…
Episode 548: MCP + Generators with Andy Andrea and Rachael Wright-Munn
Sometimes the best conference conversations start with a weird idea.
Rachael Wright-Munn and Andy Andrea join me to revisit a moment at RubyConf when Andy's experiment with schemas and MCP tools collided with a problem Rachel had been trying to solve for Ruby Events: how to make Rails generators easily accessible to AI.
What started as an excited post-talk conversation quickly became an in-person pair programming session, and eventually working MCP tooling that Rachel now uses to maintain Ruby Events. The result has reduced some event updates from more than an hour of manual work to roughly 10–15 minutes.
They dig into how MCP tools work, why wrapping deterministic Rails…
Earlier this summer, I heard from Ojal Kulkarni, a local high school student who found Planet Argon through the Portland Startup Community Slack. Her summer project was interviewing local business owners and entrepreneurs.
We’d never met before, but a few weeks later we spent an hour on a Saturday morning talking about how Planet Argon got started, what I’ve learned from running a business for 24 years, and how AI is changing the way I think about software and experimentation.
One part I especially enjoyed was revisiting how I learned to build software in the first place. I wasn’t trying to become a programmer. I wanted to sell stickers on the internet, so I kept learning whatever I…
Passenger 6.2.0

Version 6.2.0 of the Passenger application server has been released. This release addresses several NGINX vulnerabilities for deployments utilizing the bundled NGINX server (CVE-2026-42533, CVE-2026-60005, CVE-2026-56434) and one in Passenger itself with a pending CVE number. Additionally this release improves compatibility with FreeBSD.
Passenger Vulnerability
We have seen exploitation of this vulnerability in the wild at a shared hosting provider. Please upgrade as soon as possible, especially users that run Passenger as root and allow untrusted users to run arbitrary processes (i.e. multi-tenant deployments) are susceptible to attack.
If you do not run Passenger as root and your systems do…
Joanna Wang is a senior software engineer at Sixfold, where the team builds AI underwriting tools that help insurance companies gather data and assess risk. She came to Ruby on Rails after working across Java, Go, Python, and Node.
Robby and Joanna get into why the homegrown orchestration they built on state machines and callbacks turned brittle, what moving to Hatchet changed, and the tradeoffs of leaning on a gem that is no longer maintained. They also talk about what happened when the team went fully agentic, and why Rails magic is easier to understand when an agent can trace it for you.
Links:
Listen to this episode (43m) or subscribe to On Rails in your podcast…
When I first started thinking about private gem distribution, I approached the problem the way I always do, backward from bundle install. What does a developer need to make that command succeed for a private library? Three things: a source (URL or repo), credentials that work in CI and locally, and a reliable way to receive updates without breaking deployments.
Not all code belongs on RubyGems.org, and that’s okay. Sometimes the goal is internal reuse- sharing an SDK or auth client across services. Sometimes it’s a business model: you ship a private gem behind a license. Either way, the constraints are the same: authentication, delivery, and trust.
In this blog post, we’ll give an…
Way back in 2008 I started a site to track military reading lists. I needed something for searching, and I was most familiar with Sphinx, so, that's what I used.
Sphinx served me well over the last 18 years. But it runs as a separate process, and it felt like overkill to have an additional architectural component since I only have about 3000 books in the database. And PostgreSQL has a perfectly good full-text-search capability with a nice Ruby integration in pg_search. So, time to make the switch!
This article from Daniela Baron was really helpful on how to make the cutover. She was spot-on with her explaination of how calculating vectors on the fly just is too …
Last week we launched Agents on Rails and published the first benchmark report. The response was immediate: suggestions, questions, model requests, and more than a few “but have you tried…” messages. We love the enthusiasm! We want this benchmark to be useful to you, so for this run we added four new models, updated the insights, and uploaded the full traces of the first two rounds (every command, diff, and verdict).
Read on for the new results, check the updated leaderboard, or go straight to the raw runs.
But first: effort levels
We got asked this a lot and it is written in the methodology, but in case you missed it: All models were run at their provider’s default effort level.
Four…
This week I kicked off our Hanakai sponsorship drive for 2026, and shared an exciting new stretch goal — if we can raise another $15k for this year, we’ll be able to pay an honorarium to our active maintainers.
The response so far has been encouraging! We got a slew of new individual sponsors (thank you everyone!) and that’s given us some good initial progress towards that goal. Look out for tomorrow’s post on the Hanakai site for more on this, including first featured Q&A.
One thing that would really move the needle for us is finding a few more businesses to come on board. If anyone out there has ideas about this, please get in touch!While working on the announcement, I noticed our site…
I’m thrilled to be part of the program for Rocky Mountain Ruby 2026 in Boulder, Colorado.

I’ll be speaking about…LLMs? I hope you can join us!
InstiLLMent of Successful Practices in an Agentic World 🔗
Congrats on joining Hours Unlimited. The Math and Numbers team is excited to have you join us on our journey to redefine the importance of numerals. This introductory session will provide tips and tricks for best interacting with powerfuLLMachine, the next-level platform we use to unlock productivity and effectiveness.
Why some of us are still bothered about the way we write tests and what the “matcher” concept has to do with it.
During most of my Ruby career, I was that unpleasant person who honestly enjoys writing tests and is frequently concerned about the ways we write them.
This means treating unit tests like the rest of the codebase: like something that is supposed to be read by humans and something that should be written efficiently and expressively. Basically, like something that wouldn’t be boring and disgusting to read and write.
This also means that I find it useful, once in a while, to stop and reflect on why we write test code the way we write it. And can this be improved?
Let’s move…
A new account reaches the job queue before it reaches the rest of the database.
That sounds impossible the first time you see it. The account has an ID. The request log contains a successful INSERT. Yet a worker starting at almost the same moment raises ActiveRecord::RecordNotFound, and retrying the job a second later usually works.
Callbacks let an application react to persistence without putting every consequence in a controller or service object:
before_validation
after_validation
before_save
after_save
after_commit
Read from top to bottom, this looks like one lifecycle with after_commit at the far end. For a save that opens and closes its own transaction, that picture is close enough. It breaks…
CVE-2026-73330 (camaleon_cms): CamaleonCMS 2.9.1 Server-Side Template Injection via test_email Action
Ruby Instance Variables Are Not Inherited (and Why That Breaks Your DSL)
The ruby-enum gem is a small library I maintain that adds enum-like behavior to a class via include Ruby::Enum and define :KEY, value. Four pull requests landed against it recently, each fixing a different symptom, and all four turned out to be the same underlying bug: class-level instance variables set in a module’s included hook are not inherited by subclasses the way you might expect. All of these fixes shipped in ruby-enum 1.2.0.
Ruby::Enum stores its keys and values in instance variables on the class itself, set up when the module is included.
def self.included(base)
base.extend ClassMethods
base.instance_variable_set(:@_enum_hash, {})
base.instance_variable_set(:@_enums_by_val…This works fine for a single class. It gets interesting the moment subclasses or class reloading show…
My previous post walked through four bugs in ruby-enum, a gem I maintain, all stemming from the fact that class-level instance variables aren’t inherited by subclasses. The third fix, #59, made keys, key?, value?, key, value, to_h, parse and each walk up superclass and merge in a parent’s enums, so a subclass would see everything its ancestors defined. It was correct, fully tested, and shipped. It also made every one of those methods roughly 5x slower on any subclass.
def _enum_hash
if superclass < Ruby::Enum
superclass.send(:_enum_hash).merge(_own_enum_hash)
else
_own_enum_hash
end
end
This recomputes the merged hash, walking the entire ancestor chain, on every single…
Claude’s New Watermark: What It Means
If your team uses Claude to draft client-facing copy, documents, or images, you have probably seen some version of the news by now: Anthropic announced that Claude’s output will carry an imperceptible watermark in text and signed provenance metadata in files, worldwide, as its implementation of the EU AI Act’s Article 50 transparency rules. A lot of comments and interpretations have followed: detectors can now catch your AI-assisted content, you can strip the watermark out if you find the hidden characters, your clients can trace a document back to you.
Most of that is wrong, and the loudest claim, that every Claude output is already watermarked, happens to be the easiest one to check. So…
Shipping Podia’s New Shop, AI Code Woes, and a Major Rails libvips CVE
In this episode, Chris, Andrew, and David dig into their latest experiences building with Claude, from massive diffs and unnecessary view specs to the challenge of catching subtle mistakes in AI-generated code. Andrew shares what went into launching Podia’s new Shop experience, Chris breaks down a serious Rails Active Storage security vulnerability, and David earns a developer rite of passage by accidentally bringing production to its knees. Along the way, they talk Redis 6, smarter Active Record queries, testing philosophy, and why sometimes the fastest solution is still jumping into the code yourself. Hit download now to hear more!
Links
Hi, Wojtek here. Let’s explore this week’s news in the Rails.
Agents on Rails
Read the announcement and the first benchmark report.
Add support for the HTTP QUERY method
QUERY is a safe and idempotent HTTP method that conveys the query in the request content, making it suitable for queries too large or structured for a URL query string:
# config/routes.rb
query "search", to: "search#index"
match "filter", to: "search#filter", via: :query
# request handling
request.query? # => true
request.request_method_symbol # => :query
# integration tests
query "/search", params: { filters: { status: "active" } }, as: :json

Thinking of applying to next year's RubyConf Scholars and Guides program? Read on to hear from this year's Scholars about what it was like and why you should take the leap and apply!

Name:
KJ Loving
Professional Title:
Junior Developer
How did you get into Ruby? What's your Ruby story?
I got into Ruby through Code the Dream and learned on The Odin Project curriculum. I had zero background in programming but I wanted to try the backend program because it seemed a bit intimidating to me. I quickly found a loving, kind and supportive community. I couldn't have picked a better place to land.
Are there any Ruby projects you're working on that you're excited about? Tell us all about it!
Too many to list,…
Docker has made it easy to use the same environment everywhere, from development to production. But the most basic Dockerfile, where all your dependencies are lumped together in one image, has hidden costs. In this article, we’ll learn the advantages of multi-stage Dockerfiles both from a security and a performance standpoint, primarily for production images.
What is a Multi-Stage Dockerfile?
You might have a Dockerfile in your application that looks something like this:
FROM ruby:3.2
WORKDIR /app
# Install system dependencies needed to compile native gems
RUN apt-get update && apt-get install -y \
gcc \
make \
libpq-dev
# Install gems
COPY Gemfile Gemfile.lock ./
RUN bu…This is a typical single-stage setup. There’s one base image, for…
Today we’re sharing the first results of Agents on Rails, a new, ongoing initiative to measure how well today’s leading agentic coding tools (both frontier and open-weight) actually perform on Ruby on Rails codebases.
The Rails Foundation commissioned Evil Martians for this project, which will roll out in several stages over the next few weeks.
Read more about the project below, check out the leaderboard, or jump right over to the first benchmark report.
Why we built this.
The use of coding agents has skyrocketed in the past year with nearly every developer or team using AI to write code. But the options are overwhelming, with new models dropping nearly every week. The cost of running…
TL;DR
We ran 8 models against 21 atomic Rails tasks, 3 runs each. Every task runs against Writebook: a bug report, a security finding, a feature request, each written the way you’d actually file it. Read our announcement post for more information about the project.

So, as of August 2026, which model is best?
- Most accurate: Claude Opus 5, 92% of runs solved (58 of 63)*.
- Cheapest: GPT-5.6 Luna, 73% at its default medium reasoning effort, and all 63 of its runs cost 91 cents combined. Not a typo.
- Fastest: Luna again, at a median of 3.3 minutes per run task.
- Best combination of all three: GPT-5.6 Sol: 84%, about $0.52 and five minutes per run.
* Claude Fable 5 might lead with…
GHSA-mwm8-39rw-8826 (sqlite3): Use-After-Free in SQLite Aggregate Arguments in Heap-Allocated Argument Array
Speeding Up (small) Ruby Hashes
Something I must confess is that I absolutely hate writing these blog posts. It’s not quite as bad as having to give a conference talk, but it’s up there on the list of activities that feel like pulling teeth to me. Not that I’m not proud of the result. I absolutely am. But the process of writing them is very painful for me. It’s particularly true of the very first sentence, as the post progresses, it gets a bit easier
Yet, I force myself to do it, because it helps me think about problems, and “compile” knowledge in my head. I’m so terrified of posting something wrong or inaccurate that I tend to double-check some long-held assumptions, dig into more details about how some things are…
A new attempt to fork Rails
#813 — August 13, 2026
🗓️ A scheduling note: We're taking a summer break next week, so we'll be back on August 27. Catch you then!
__
Your editor, Peter Cooper
Ruby Weekly
Ruby 2D 1.0: SDL3, WebAssembly, and a Comeback Story — After three years dormant, Tom Black's "Square.new-and-it-appears" graphics gem gets a rewrite with SDL3-powered GPU rendering and the ability to compile experiences to WebAssembly (live examples). Learn how to use its DSL here or read Tom's story of resurrecting the project.
Tom Black
😅 I tested it out by making a little Mario Paint-inspired paint app (above) and I learnt I can't draw…
The eleven-shade color scale from Tailwind CSS is one of those ideas I keep stealing. You know the one: 50 through 950 gives you enough stops for backgrounds, borders, hover states, text, everything. I use it even when I’m not using Tailwind.
But I almost never use the defaults (your site/app ends up looking like every other site built by LLMs).
The fix is not complicated. You don’t need a color theory degree or a five-color palette generator (you know the ones 🥹). You only need two or three color scales, and you can derive them all from a single value.
How to choose your brand hue
Rule of thumb: pick a color that fits the problem, not your personal taste (I like pink but not use it all…
Beyond travel_to: The Block-Scoped State Pattern Hidden in Rails Testing August 12, 2026 Rails developers often use travel_to without thinking much about how it works. travel_to Time.zone.parse("2026-08-12 10:00") do # Test code runs as if it were 10:00 end The API is simple: change the perceived time, run some code, and automatically return to the … Continue reading Beyond travel_to: The Block-Scoped State Pattern Hidden in Rails Testing
Ship agent skills like packages: discovery index, digests, and install sources

How to publish agent skills so any AI coding agent can find and install them: the .well-known/agent-skills/index.json discovery index, SHA-256 integrity digests, single-file vs multi-file vs bundle packaging, and every install command. Worked from the catalog we just open-sourced.
Two posts ago, an AI startup found us because Claude, which recommended Evil Martians when they asked for a senior dev agency. One post ago, we measured the traffic behind that. Over two months, coding agents read evilmartians.com more than twice as often as people did: 268,000 agent…
Maintaining an organizational knowledge graph with an LLM and event sourcing
Maintaining an organizational knowledge graph with an LLM and event sourcing
Organizations are surprisingly good at forgetting.
Decisions are made on calls, insights get buried in Slack threads, and a month later no one remembers why things are the way they are.
Arkency is no exception.
Weekly calls, ad-hoc meetings, our book clubs, Slack discussions, GitHub mentions, email inbox - we could use some support in organizing all those signals.
Then Ruby Community Conference 2026 happened in March.
In Kraków, Obie Fernandez showed some parts of his NEXUS system.
He had already described it on his blog back in January, but the conference was where I first came across it.
That was the push I…
When it was…
Yet again instead of tweets, a blog post. The backlog got out of hand - 40 of them this time.
Usual caveat: every number below is whatever the author measured on their own machine with their own workload. Some are microbenchmarks. Don't compare them against each other, and don't assume they'll show up in your app. Click through if you care about methodology.
byroot is still speedrunning Ruby and Rails
Jean Boussier shows up often enough that he gets a section instead of bullets scattered through the post.
-
Make Monitor a core class - giving it access to Ruby's internal routines strips out a chunk of overhead.
Monitor#synchronizegoes from about 19.8M to 23.7M calls a second; a plainMutex…
Andy Kroll joins the podcast to talk about Brighton Ruby, the impact AI is having on software development, and how the changing technology landscape is affecting everything from conference budgets to engineering teams.
Andy shares how tools like Claude Code have changed his day-to-day work, making previously neglected projects more achievable while putting even more emphasis on code review, judgment, and maintaining a sustainable Rails application. They also dig into one of the harder questions created by AI: how do you interview software engineers when take-home coding exercises and traditional technical tests are increasingly easy to hand off to a model?
Andy explains how…
The slack-ruby-client library, an open source Ruby gem I maintain, runs a scheduled GitHub Actions workflow that regenerates code from Slack’s API definitions and opens a pull request with the diff. The commit message and CHANGELOG entry used to be a generic “Update API (2026-08-11)”, which told a reviewer nothing about what actually changed. Here’s how we taught the workflow to describe its own diffs, using GitHub Copilot CLI, which open source maintainers can get for free.

The Idea
The workflow already computes a diff before opening the pull request. Instead of a boilerplate commit message, we pipe that diff through an LLM and ask it to summarize what changed, then use the response as…
thoughtbot around the world, meet us at upcoming events
Fall is shaping up to be a busy season for thoughtbot. Over the next two months, thoughtbotters are speaking, attending, and hosting events across six cities on two continents. If you’re nearby, come find us.

XO Ruby Vancouver, August 15, Vancouver, Canada
XO Ruby Vancouver kicks things off. Fernando Perales will be speaking on “The Ruby Guide to Responsible LLM Integration,” a talk about the production challenges of wiring large language models into Ruby applications: malformed input, data leaks, prompt injection, outages, and rate limits, and the patterns that keep things stable once real users start hitting them.
EuRuKo 2026, September 16-18, Brno, Czech Republic …

Are you treating your users fairly? They could be stuck in the queue while a greedy user monopolizes resources. And you might not even know it! In this post, you’ll see if it’s time for you to take background job prioritization seriously, and how to make it fair for all users.
Are you treating your users fairly? They could be stuck in the queue while a greedy user monopolizes resources. And you might not even know it! In this post, you’ll see if it’s time for you to take background job prioritization seriously, and how to make it fair for all users.
Ruby Runway Spotlight: Adam Dalton, Andy Davis, and Larissa Dalton of Stowzilla

This is part of an ongoing series of Ruby Runway Spotlights, celebrating the founders who took part in the inaugural Ruby Runway Showcase at RubyConf 2026. Each spotlight is a chance to hear directly from the builders turning Ruby into real, live businesses, and to cheer them on as they keep going.

Tell us your name, your startup, and what it does in one or two sentences.
Stowzilla is your personal warehouse service. Know what you have, and get value from the things you no longer need.
What problem are you solving, and who feels it most? How does your Ruby-powered solution change things for them?
We're solving the problem of getting valuable stuff to people who can use it, and giving space back…
The following is one of those posts where I share some concrete memories/experiences that I associate with some musings, but otherwise doesn’t really have a strong point other than I want to write it down.
When I worked at Code for America, I helped design and deliver two different technical interviews.
The first interview, which I feel confident I can take credit for wholly, was security related. Me, the interviewer, would first have the candidate read about Cross Domain Referer Leakage, and then we’d talk about it:
- How would you summarize the vulnerability in your own words?
- Describe to me a scenario for how an attacker would exploit this.
- Can you think of…
RubyLLM::Schema Is Now Schematist: A JSON Schema DSL for Ruby with Full Draft 2020-12 Coverage
I want to make Ruby the best language to work with LLMs. Part of that is a great JSON Schema DSL.
Schematist is a general purpose JSON Schema DSL that emits Draft 2020-12 schemas. Describe an API payload, a config file, a contract between two services, or the structured output you want back from a model. Trapping that inside another gem’s namespace was a disservice to anyone looking for a great JSON Schema DSL, so it got its own name.
gem 'schematist'
It Emits Actual JSON Schema
This is the breaking change.
to_json_schema used to return this:
{ name: "PersonSchema", description: nil, schema: { type: "object", ... }, strict: true }
That’s not a JSON Schema. It’s OpenAI’s response_fo…
Sponsor Hanakai in 2026!
It’s been a whole year since we ran our first sponsorship drive. We’ve been hard at work since then: we shipped Hanami 2.3, unified our ecosystem and launched Hanakai (plus this beautiful new site!), and shipped Hanami 3.0, our most complete release ever. (If you want to catch up on more behind this, hear me on the Dead Code podcast.)
Thanks to our sponsors’ financial support, I’ve been able to maintain at least one full working day on Hanakai every week over the last year. This has been crucial for achieving all of the above. It’s an honour to spend this time serving our community, and a privilege I don’t take lightly. This is why I also spent the last year writing weeknotes, to make our…
Things move fast. Almost daily, we stop doing some basic routine and automate it instead. Engineers aren’t coding anymore, just prompting. PMs tell the AI what the feature is about, and an agent writes the ticket. On plenty of teams a bot now reviews the pull request an agent opened, which makes everyone else a spectator of a conversation between two AIs.
This isn’t just a personal habit shifting. It has a name. Philosopher Avigail Ferdman calls it deskilling, and in her 2025 paper “AI deskilling is a structural problem”[1], she argues something important: this isn’t a matter of individual willpower. Expecting people to resist convenient automation and cultivate their capacities on their…
Continuations 2026/32: Set the table
My main goal for the last week preparing to kick off our sponsorship drive. I finished drafting the first post, lined everything else up, and now we’re ready to go! Stand by for that first post—in just a few hours!
I spent some time reviewing Ryan’s “Hanami for Rails devs” guides, and relocated them so they appear right below our main Getting started guide—these will be an important part of helping our future users! There’s still a bit of feedback left to sort out, but hopefully these can merge soon.
I put together some notes to set the table for what the team and I can work on for Hanami 3.1. This is going to be a slightly shorter development cycle for us to make a second release this…
This week, Anthropic shipped a new messaging feature to Claude Code. It sounds innocuous enough:
Cross-session messaging lets Claude deliver a message from one of your Claude Code sessions to another. When a change in one session breaks what another is building on, Claude can warn that session before you notice. When one session settles a question another is blocked on, Claude can send the answer across.
And because I sometimes have multiple agents working in the same project simultaneously, it didn't take long for them to start coordinating behind my back so as to avoid interfering with each other's work:
Also, another Claude session (working on performance rugs) pinged mid-turn; I told…
When we think about Ruby code coverage, our go-to gem for this is SimpleCov, which works great when the test suite uses Minitest, RSpec, Cucumber, Capybara, and all these tools that are integrated with Ruby and Rails. But many applications also use other tools like Playwright or Cypress to run e2e tests, and we can’t use SimpleCov the same way.
Most of the time, what we have seen is that the Ruby code executed when running these tools ends up left behind and not being counted for the total code coverage, even though we know the code is actually being tested.
Sample Application
To make it easier to try this, we created a sample application that uses the cypress-on-rails gem along with…
AI Adoption Is More About Culture Than Tools
A few weeks ago, we sat down with a potential client for a project kickoff conversation. The goal was to find out how we could help them integrate AI into their company. Their whole team joined the call, about 15 people, and within the first ten minutes, it was clear everyone had a different idea of what “using AI” meant to them.
One person wanted an easier way to schedule meetings. Another wanted AI to summarize call notes. A few wanted to search through years of client history. Some of what people described, honestly, was closer to plain automation than a need for artificial intelligence. More than a few people in the room were hesitant to…
Building Virtuous PDF: How Gusto Replaced a Deprecated Library with a Modern PDF Microservice

The problem with our old setup
PDF generation is a core part of Gusto’s business. To serve our customers, we generate reports, invoices, tax documents, employee handbooks, and more. Many of these features relied on a now-deprecated library: wkhtmltopdf.
That reliance had become a liability. Maintenance on the library had stopped, which meant no more security patches. It rendered HTML using WebKit, an engine that had drifted away from how modern browsers display the same markup, so our PDFs didn’t always come out the way we expected. And because PDF generation is memory-intensive by nature, it put pressure on the other services it shared resources with.
Why build a new service?
We decided to…
DNS enumeration with Ruby
I love Ruby and it is my goto scripting language. Even in the age of AI, I like to write short custom scripts for my tool arsenal. One way to find subdomains of a potential hacking target is to initiate a DNS zone transfer. You can use various shell tools for this, but if it is part of a process(my case), it might be easier and more flexible to just script it in Ruby. I decided to use the dnsruby gem to save some work, otherwise I would need to do a TCP connection to the nameservers myself. For the sake of demonstration, I converted my script into a command line one, that will accept 2 parameters, the host and an optional IP address of a nameserver:
CVE-2026-71847 (json): Ruby JSON - JSON::ResumableParser#partial_value dereferences a freed input buffer and crashes on truncated duplicate-key streams
The method
This process applies the scientific method to a defect. The six phases are the steps of that method. They carry the names a developer uses.
Scientific method Phase You produce
----------------- ----- -----------
Build the apparatus 1. Build a feedback loop one command that goes red on this bug
Observe under control 2. Reproduce and minimise a minimal case that repeats
State the hypotheses 3. Write the hypotheses 3 to 5 ranked causes, each with a prediction
Run the experiment 4. Instrument one probe per prediction, one variable at a time
Confirm the result 5. Fix and add a test a…Rails is done
If you need more context on why Rails needs a new leadership, here is David Celis summing it up a year ago, Paul Battley a few weeks ago, and—even though it is hard to believe—it even got worse since then.
How could a fork even work?
Rails is a huge code base and has multiple engineers who can invest significant work time into improving it. How could a few people fork and maintain it in their free time? Because Rails is done. Since I started to update The Rails 5 Way to Rails 6 (and then later 7 and 8), I’ve been monitoring the changes to Rails closely:
If you generate a Rails application with rails new --minimal, you only get the core parts of the framework (railties, actionpack,…
transaction is one of the few Active Record APIs that reads like a promise. Wrap the work in a block, and either all of it happens, or none of it does.
An account upgrade shows where the reading breaks:
Account.transaction do
account.update!(plan: "growth")
ProvisioningClient.enable_growth_features(account.external_id)
AuditEvent.create!(account:, action: "plan_upgraded")
endA validation added to the AuditEvent a week earlier rejects the new audit record, so create! raises ActiveRecord::RecordInvalid. The SQL log ends the way it should:
BEGIN
UPDATE "accounts" SET "plan" = 'growth' ...
INSERT INTO "audit_events" ...
ROLLBACKThe account row goes back to starter, so the ticket is closed as…
Direct link to podcast audio file
We cut our trip a day short, so I found myself with a totally free day with no plans. Naturally, I wasted it by recording a 3-hour podcast. Dang.
I always enjoy shooting the shit with/at you, and if you'd like to be a more active participant in the shit-shooting, then hit me up at podcast@searls.co. Really, I'll be nicer to you than I am to Sam Altman and Tang Tan. I promise.
Back to manually writing links. The zen of monotonous input tasks is suddenly something to be cherished in the current era.
After Rails’ Dear Leader DHH once again espoused far-right views on his blog (which I’m not going to link to here), some of the Ruby community said “enough is enough” and decided to fork Rails into a project called Amiko. I don’t want to mince words here, so I’ll talk straight: I think this is a vain attempt at virtue signalling, and will ultimately end up achieving very little.
The Amiko project has started out this fork by renaming all the Rails things into Amiko flavoured things. They have amiko-pack, amiko-view, and so on. All the rails commands are now amiko commands. The structure of the framework remains the same, so far.
The momentum behind the Rails framework itself is monumental…
Some things that should have worked all along finally do… like alias_attribute in associations, pluck on unsaved records, search_field with autosave: true. The rest of the week went into sharper SQL logs, sturdier job continuations, and more Ractor-ready registries. Here’s what’s new in Rails:
Matz is coming to Rails World 2026!
Ruby creator Yukihiro “Matz” Matsumoto is coming to Rails World 2026! He’ll join DHH, Aaron Patterson, Robby Russell, and the rest of the lineup in Austin this September, and the full conference agenda is now live. If you’ve been waiting to see what’s planned before grabbing a ticket or planning your schedule, now’s the time to take a look.
SF Ruby 2026 with Irina and Vladimir
Irina Nazarova and Vladimir Dementyev from Evil Martians return to preview the second annual SF Ruby Startup Conference and share what they learned from bringing the event to life for the first time. They discuss the conference’s new focus on ambitious builders, the importance of creating meaningful connections for attendees, and why Ruby on Rails remains a powerful foundation for startups tackling difficult, real-world problems. The conversation also explores open-source innovation, AI-assisted development, hidden pockets of Ruby adoption, and how the community can help the next generation of companies confidently build and grow with Rails. Hit download now!
Links
Hi everyone!
Rails World 2026 is just 47 days away, and we have a few fun updates for you. If you haven’t already, you can grab your ticket here.
Now for the updates:
Matz is coming
Big news first: Matz is coming to Rails World 2026! He’ll sit down with DHH on day 2 for a fireside chat. It’s been two years since the last chat in Toronto, and so much has changed since then. We’re living in a different world, so we wanted to bring these two together on stage again to chat about Ruby, Rails, AI, and what the future holds for programming.
Attendees will be able to submit their questions beforehand. This session was made possible by the generous support of our Event Partner and sponsor, Sho…
August 6, 2026 Most Rails applications that implement multi-tenancy eventually face the same question: Where should the PostgreSQL tenant context be established? Many implementations set the tenant at the controller or middleware level. While that identifies the current tenant, it doesn't necessarily guarantee that every database connection carries the correct PostgreSQL session state. A cleaner … Continue reading Hooking into ActiveRecord’s Connection Pool: A Clean Way to Enable PostgreSQL Row-Level Security
Where are the benefits of using AI? Last Monday I woke up with this question on my mind, I, from my corner of the world far away from big techs, millions of dollars, datacenters, posts on X and LLM-generated posts on LinkedIn.
Eight years ago I started working as a programmer, two at the company where I am currently and one since they started pushing us to use AI to accelerate the development process. I don’t deny that my speed for spitting out code has increased, solving problems has become faster and reaching solutions is less complicated. But what sense does it make if I drift away from what I like most: using my capacities and knowledge to write code that solves a problem and then,…
#812 — August 6, 2026
Ruby Weekly
Shrinking Ruby Hashes — Hash uses 2-4x the memory of a Struct holding the same data. Ruby committer Jean Boussier digs into why, looking at the layout changes from Ruby 2.3 to now, and shows off the patches that could shrink small hashes in Ruby 4.1.
Jean Boussier
Make Your Next Rails Crash Make Sense — Errors, N+1 queries, slow SQL, Sidekiq jobs, and host metrics in one Ruby gem. Every feature on every plan, predictable pricing, and real engineers on support. 30-day free trial, no credit card, two-minute install.
AppSignal sponsor
If you work on Rails for a living, you clone repositories you didn’t write all week long: a gem you’re debugging, a client’s application you’re about to audit, a bug reproduction attached to an issue. For years, opening one of those in your editor was the safe part. You were reading someone else’s code, not running it, and the only real rule was to not run anything until you had looked.
That rule quietly stopped being enough. AI coding editors like Claude Code and Cursor read project-local configuration the moment you open a repository, and some of that configuration is executable. A repo you cloned five seconds ago can hand your editor a command to run before you have read a line of it,…
You run bundle update, kick off a build, and asset precompilation stops on this:”
cssbundling-rails: Command install failed, ensure bun is installed
Tasks: TOP => assets:precompile => css:build => css:install
Except your application uses Yarn. It has always used Yarn. Nothing in the project references Bun, and nobody on the team added it.
This is not an exotic edge case. It can happen to ordinary Yarn applications, and it lingers because the fix has been merged upstream but never released. In this post, we’ll walk through why cssbundling-rails misidentifies your package manager, and how to unblock your build.
The Short Version
cssbundling-rails 1.4.3 added yarn.lock to the list of……
You’re evaluating AI vendors for a company-wide rollout, and every conversation ends the same way: it’s safe, it’s anonymized, we have guardrails. We’ve watched this play out recently, and the questions don’t stop at that answer. Safe how, and which guardrails are actually in place to prevent a leak? Vendor reps tend to stall on the specifics: how access is managed at the level of an individual AI agent, not just the account, and which models and model providers are actually involved, with what safety assurances at each one, not because they’re hiding something, but because “we have guardrails” is often as far as the pitch was built to go.
That gap is worth taking seriously, because the…
This is part 2 of a two-part series. Part 1 covered controllers and lifecycle.

Controllers connect and disconnect. That is not useful on its own. The value comes from three things: referencing elements inside the controller, handling events without inline JavaScript and reacting to data changes. Stimulus calls these targets, actions and values.
Each maps to a distinct JavaScript feature. And none of them repeat the tricks from part 1.
Here is the code. See the full commit on GitHub.
Targets: dynamic getters
A target is a named element inside a controller’s scope. Declare it in the class and get a getter for free:
class HelloController extends Controller {
static targets = ["name",…
The getter this.nameTarget returns the first element…
The RubyGems guides at guides.rubygems.org are read by more than humans these days. AI agents fetch them to answer questions about building, publishing, and installing gems. Evil Martians’ Ruby/Rails LLM discoverability scorecard asks how easily an agent can find and read Ruby documentation, and the guides had no good answer. There was no machine readable index, and no way to get a page without its navigation and markup. This week we merged three changes that close both gaps.
The first change adds sitemap.xml and robots.txt (rubygems/guides#523), giving crawlers a complete map of the site. The robots.txt allows everyone, AI crawlers included. Some documentation sites have gone the other…
Shrinking Ruby Hashes
As you may know, one area of Ruby performance optimization that particularly interests me is memory usage.
Given that most Ruby deployments rely on fork, improving Copy-on-Write performance is generally where you get the
biggest bang for your buck, but that only helps with the somewhat static part of an application heap.
A significant contributor to memory usage is also the transient memory that is allocated during a request or job cycle and released soon after. As such, it’s also interesting to keep an eye out for opportunities to make various Ruby objects smaller.
And the Ruby object type that’s probably the biggest contributor to memory usage is likely Hash.
Hash instances are…
Replacing a jQuery dropdown with an accessible one, and keeping the design identical
Welcome Rubyroid Labs!
We're excited to welcome Rubyroid Labs as a Ruby Alliance Supporter, joining a growing group of organizations investing in the long-term health of Ruby and its open source ecosystem.
Every day, millions of developers rely on RubyGems.org without thinking twice about it. That's exactly how great infrastructure should work—reliable, secure, and always there when you need it.
Keeping it that way takes a community.
Since 2013, Rubyroid Labs has helped startups and enterprises build and scale Ruby on Rails applications while actively giving back to the Ruby community through conferences, education, and technical content. Now they're expanding that commitment by contributing engineering resources to…

Tailwind CSS has become a very popular CSS framework, and it can speed up development. But using it without proper caution can add mayhem to your code. Learn best practices to avoid getting swept away!
Working with Tailwind CSS is pretty fast and easy (that's why it's received such wide recognition). You just paste a list of different classes in your HTML—and your interface immediately becomes attractive! But, as the application grows, the lists of classes grow. Then, one day you realize you can't understand your code, you're confused with the structure of the application and…
I'm happy to announce that Karafka 2.6 and Karafka Web UI 1.0 have just been released.
For those new here: Karafka is a Ruby and Rails multi-threaded, efficient Kafka processing framework, and its Web UI is a monitoring and management dashboard that ships alongside it. As with every release in the 2.x line, this is a continuation rather than a rewrite - you upgrade, apply a couple of small changes, and keep going.
On the surface, 2.6 is a focused set of features - redesigned Declarative Topics, dynamic worker pool scaling, a new low-level offsets API, and lag compensation for paused partitions. Underneath, it is the largest internal reorganization the framework has seen in years. Almost…
Rails Foundation Executive Director Amanda Perino joins David to preview Rails World 2026, the conference’s first year in the United States.
Amanda shares how the team is bringing Austin’s personality into the event through live music, barbecue, sponsor experiences, a mechanical bull, the returning Buzzsprout podcast booth, and Rails World’s biggest lightning-talk stage yet. She also discusses the opening keynote livestream, the lightning-talk CFP, ticket availability, and what attendees should expect as the conference approaches.
The conversation then turns to the Rails Foundation itself. Amanda explains how the rapid growth of AI has forced the organization to reconsider how it…
A year at 37signals
A year ago I had my first day at 37signals (the people behind Basecamp, HEY and Fizzy).
This was a dream come true for me.
I wanted to work there ever since I read Rework over a decade ago. The books, podcasts and talks that followed showed me that we also share a similar philosophy towards work and the craft of coding. That just cemented my resolve.
Not to mention that it's the birthplace of Rails! The single piece of software that made me decide to turn my programming hobby into my career.
I had an incredible year, so I want to share how I got here and what I learned that might not be obvious when looking from the outside-in.
Getting the job
I'm not sure how many times I applied for a job…
Finally, Netflix you can chill.
4.0.18 Released
RubyGems 4.0.18 includes enhancements, bug fixes and documentation and Bundler 4.0.18 includes enhancements, bug fixes, security and documentation.
To update to the latest RubyGems you can run:
gem update --system [--pre]
To update to the latest Bundler you can run:
gem install bundler [--pre]
bundle update --bundler=4.0.18
RubyGems Release Notes
Enhancements:
- Check the resolved parent directory before extracting old format gems. Pull request #9755 by hsbt
- Installs bundler 4.0.18 as a default gem.
Bug fixes:
- Call Kernel.format explicitly in Gem::Deprecate wrapper. Pull request #9714 by hsbt
Documentation:
- Point bundler.io URLs at guides.rubygems.org. Pull request #…
You saw the advisory for CVE-2026-66066, the Active Storage vulnerability in the way Rails processes image variants with libvips. You bumped activestorage to the patched version, ran your tests, deployed, and moved on. That is the responsible thing to do, and for most Ruby vulnerabilities it would be the whole job.
This one is different. The patched version of Active Storage will not run on an old copy of libvips. It raises an exception during boot and refuses to start:
/usr/local/bundle/gems/activestorage-8.1.3.1/lib/active_storage/vips.rb:36:in '<compiled>': libvips's unfuzzed operations are not safe to use with untrusted content, and Active Storage cannot disable them. Disabling them r…libvips is a system library that lives…

This is part of an ongoing series of Ruby Runway Spotlights, celebrating the founders who took part in the inaugural Ruby Runway Showcase at RubyConf 2026. Each spotlight is a chance to hear directly from the builders turning Ruby into real, live businesses, and to cheer them on as they keep going.

Tell us your name, your startup, and what it does in one or two sentences.
I'm Joe Masilotti, and I help Rails developers deploy to the mobile app stores. Ruby Native builds real iOS and Android apps from the HTML and ERB you already have, without writing Swift or Kotlin.
What problem are you solving, and who feels it most? How does your Ruby-powered solution change things for them?
Your customers…

We designed and shipped a fresh AppSignal homepage in code, then validated it in an A/B test with a 14% lift in activated users.
AppSignal is an established APM platform used by thousands of engineering teams that combines error tracking, logs, and uptime in one product. For its 2026 homepage, Evil Martians imagined a bold creative direction, built it with LLMs, and shipped it straight into an A/B test. Early data shows…
In a previous post, AI Assistant for Our Blog Writing Process, I introduced the assistant we built to help with our blog writing. At the core of that assistant is an MCP server, which serves as the source of truth for both of our blogs. It exposes that knowledge through tools the client can call and documentation the client can read.
Getting an MCP server running is the easy part. Every quickstart, in every language, gives you a server that runs as a subprocess on your own machine and disappears when the client exits. That’s enough to experiment locally, but it’s a long way from something a team can rely on. Once you want to deploy it, questions about where it runs, state management,…
If your business runs a support chatbot, or if someone on your team uses an AI tool to draft marketing copy, you already have an AI system in scope of the EU AI Act’s transparency rules. You don’t need to be doing anything exotic or high-risk to be covered. As of August 2, 2026, these rules are binding, and the European Commission’s AI Office, together with national market surveillance authorities, can enforce them.
That catches a lot of businesses off guard, because most of the coverage of the AI Act so far has focused on high-risk systems: hiring tools, credit scoring, biometric surveillance. Those obligations are real, but they’re not due for a while yet, more on that below. The…
Why HTTP Introduced the QUERY Method: Solving the Limitations of GET and POST
RSpec Expectations: You're Probably Using the Wrong Matcher August 3, 2026 If you've been writing Ruby tests for a while, chances are you've reached for eq more times than you can count. While it works for many scenarios, RSpec Expectations offers a much richer vocabulary for expressing intent. Choosing the right matcher isn't just about … Continue reading RSpec Expectations: You’re Probably Using the Wrong Matcher
How to programmatically upload attachments to GitHub Issues, Pull Requests, and Comments, finally, for now
It’s possible to programmatically upload images to GitHub Issues, Pull Requests and Comments via automation. Finally, though maybe mistakenly, I dunno.
It’s fairly well known that for the longest time, GitHub has not had a programmatic interface for uploading images and attachments. It’s possible in the browser, by dragging-and-dropping your image, but not via something you can script or curl. That’s been a bummer for lots of GitHub Action-powered systems you might imagine, like: automatically attaching demo screenshots or videos on PRs for new features, or attaching failure screenshots or visual diffs from browser tests.
Until now, I guess. Here’s the unofficial,…
In this episode of On Rails, Robby is joined by Aaron Patterson, better known online as Tenderlove, a senior staff engineer on Shopify’s Ruby infrastructure team and a longtime contributor to both Ruby and Rails Core. Aaron and Robby chat about how Ractors are finally bringing true multi-core parallelism to Ruby, the proposal Aaron has pitched to RubyGems.org for content addressable gems that could make bundle install dramatically faster, and the real reasons gems reach for native C extensions in the first place.
They also have a candid conversation about how Aaron actually uses AI day to day, from digging through unfamiliar code at Shopify's scale to building a JPEG encoder almost entirely…
From plausible to production-ready: schema-grounded code replaces hallucinated props with verified, type-safe components.In our previous post, we treated Zod schemas as agent-readable contracts. But a schema is just a hypothesis; without tests, you’re shipping vibes. This post dives into how we operationalized these schemas, set up a testing suite on Braintrust, and started scoring AI output against our design system.
We set up an experiment with 167 hand-written prompts across 25 components, plus a second dataset built from real engineer requests. Each prompt is a plain-English UI request (e.g., “a primary action button that confirms saving”). The model receives the component’s schema and…
I’m almost back to normal weeks again. A few important life things have continued to impose on my ordinary OSS time, but I’ve been pressing forward with as much as I can.
I merged a nice little improvement to how the
hanamiCLI invokes thepsqlCLI. Another great improvement from mddelk — thank you!Reviewed this internal hanami-cli improvement that switches to throws to allow commands to halt CLI execution, rather than direct exit statements. This should improve some CI flakes, but is also a much nicer approach overall. Thanks Paweł!
More in Katafrakt korner: I reviewed Paweł’s work to make our database tooling work with JRuby, which is looking promising. Paweł also merged a bunch of d…
Frequently Played 🔗
I tend to listen to the same songs or albums on repeat that are evocative of how I’m feeling or what’s going on with me. Here is what I’m currently listening to over, and over, and over, and over, again.
Atlantic City 🔗
I just got my hands on the Expanded Edition of Nebraska. Easily a top 5 Springsteen album for me. I’m not sure the Expanded Edition added much for me though.
Down here, it’s just winners and losers
And don’t get caught on the wrong side of that line
Free 🔗
This is still, I think, the most important song released this decade to me.
The feeling comes so fast and I cannot control it
I’m on fire, but I’m trying not to show it

