Hussain Akram is an engineering manager at Donorbox and Antonio Carlos de Souza (A.C.) is its chief architect, working on a Rails app that has helped nonprofits raise money online and in person for more than a decade.
Robby, Hussain, and A.C. get into how Donorbox handles serious traffic with a deliberately boring setup, why the team moved CI back onto developers' machines, and how they're pulling older parts of the app back toward Rails defaults. They also talk about how they use agent docs to steer AI tools toward the patterns they want the codebase to follow.
Links:

Look at those text effects: wow would you build them?
My first answer, somewhere in the 2000s, would have been Flash. A timeline, some easing curves, spooky rippling text for every band MySpace page. 🤘 After Flash came many other options: jQuery plugins, canvas pixel picking, shaders in a giant WebGL library for one ripple of text.
Luckily today all you need fits in two SVG primitives and one line of CSS.
For a while now, you can apply SVG filters to regular HTML:
filter: url(#my-filter)
The browser then renders your element through that filter. And SVG filters can do wild things. The wildest of all: feDisplacementMap.
How feDisplacementMap works
Here’s how feDisplacementMap works. It…
Ruby 4.0.8 Released
Ruby 4.0.8 has been released.
This is a routine update that includes bugfixes. Please see the GitHub releases for further details.
Download
-
https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.8.tar.gz
SIZE: 23947459 SHA1: f79bc8217dd0edd7ecc0c1c0cb57e64a906258a5 SHA256: 0968e2ac4cbd6f1fd85d3092aed66cd3c2d8ba4a5e2493d6e6c6cb0c431897d2 SHA512: 011b741c8fe3160643739f8fd88f3a69b198260dabcd3cb791c1ffacdfae7b48f6b2ca365ea97198d5dcb13fc839533ec1e83bab76f38c25203a7a3b6e665e8b -
https://cache.ruby-lang.org/pub/ruby/4.0/ruby-4.0.8.tar.xz
SIZE: 18019152 SHA1: 24404aa1371a1f5a28bfcc8ac4331bd744810954 SHA256:…
After adding spelling checks to RuboCop, I wanted the same thing for Rust.
Introducing dylint-spellcheck, a Dylint library for checking spelling in Rust comments, Rustdoc attributes, Markdown, and plain text. It uses the Rust implementation of Kotoshu and ships an American English dictionary. The idea is the same as the Ruby version: fix actual typos, accept project-specific vocabulary, and run spelling alongside the other lint checks.
Getting Started
The examples below use released 0.1.0. Install Rust through rustup, then install Dylint:
cargo +stable install cargo-dylint dylint-link --version 6.2.0 --locked
Add the library to your project’s Cargo.toml:
[workspace.metadata.dylint]
l…geneva_drive is the first thing I’ve put out for money on my own, without an org behind my back - and a rollercoaster on many fronts. One of the less obvious ones is the actual distribution: how does geneva_drive get to your servers or dev machines, once you have that ticket?
It works via paquette - my little engine for serving libraries. Here’s how it got made, and why.
I am currently available for contract work. Hire meto help make your Rails app better!
The idea is simple: you purchase access to some distribution point for a commercial package, you point your package manager to it, and your package management system (bundler or npm or what have you) does the…
Th…
Rails is a JIT compiler
The title was bait to get you to open this article. But fear not! We will be generating code at run-time today. (See the PR for a sneak peek.)
Sam popped into the JIT channel asking how we might optimize Rails enums in Roundhouse, motivated by the following code snippet:
class Order < ActiveRecord::Base
enum :status, { pending: 0, paid: 1, shipped: 2, refunded: 3 }
def shippable?
paid? && !refunded?
end
end
In particular, there is a lot of dynamic behavior going on with the code
generated by Rails enum and Sam wanted to know if inlining it all away in an
(external-to-Rails) build step would help.
That didn’t sound right to me because I thought that:
- Rails got a lot…
https://avdi.codes/190459-2/?utm_source=rss&utm_medium=rss&utm_campaign=190459-2
To come in as a technology leader and say “AI should never be used” is to make myself unemployable.
Bluntly, I can’t afford that right now. My healthcare costs equal my mortgage, I’m not part of an existing social safety net and I cannot relocate to somewhere more favorable to not earning an income.
naildrivin5.com – David Bryant Copeland’s Website: I’m Gonna Write About AI So I Can Process What Is Going On
Same.
I replaced this blog’s Python spell checker that took more than three minutes to run with the new rubocop-spellcheck.
I really love RuboCop for its standard approach to linting and auto-correction, which solves the difficult problem of deciding between tabs and spaces (use defaults). My typical implementation in Ruby projects is to add a standard .rubocop.yml, run rubocop -a, ask an AI to fix easy fixable violations, then run rubocop --auto-gen-config to mark all remaining ones as an exception. Why should spelling be any different?
Introducing rubocop-spellcheck, a RuboCop plugin for checking spelling in Ruby comments, strings, identifiers, Markdown, RDoc, AsciiDoc, and plain text. It…

Tips and tricks on writing robust evals for coding agents that test apps whose code we've never seen: different UI/UX contract strategies, UI mutation testing, browser-based E2E verification gotchas.
The Agents on Rails is an LLM benchmarking project governed by the Rails Foundation. They commissioned Evil Martians to design and implement the evaluation tasks and the tooling to run trials at scale. You can follow the Ruby on Rails blog for progress and insight reports, with the up-to-date leaderboard on the official website. On our blog,…
DatabaseCleaner was a very popular gem that helped you keep a clean database between tests. However, newer versions of Rails removed the need for this tool for most cases. Even so, many applications that always used it still use it to this day. Let’s talk about what it does, why it was needed, and why you probably don’t need it anymore, and when you still might.
What is it
DatabaseCleaner is a gem that you can use to ensure that every test you run starts with the expected database state. DatabaseCleaner supports different databases: relational databases (MySQL, PostgreSQL, SQLite, MariaDB, for example), MongoDB, and Redis. In this article we’ll focus on relational databases which is the…
Allowing an AI to write code that you then ship without considerate review causes some anxiety. How do you know the code works? How do you know it isn’t doing something strange you didn’t ask for?
It feels like you can’t totally trust it. However, a product manager or engineering leader doesn’t review the code developers are shipping. They are trusted. What’s different?
Allowing an AI to write code that you then ship without considerate review causes some anxiety. Engineering leaders do this all the time with their team members - they don't review all the code. What's different?At Stitch Fix, we did a lot of corporate training on company values. That may sound horrible, but it…
What does it mean to be a software developer when writing code is no longer the central part of the job? Jessica Kerr and Avdi Grimm join David Hill for a conversation about the changing work of software engineering—and how to navigate that change without losing the curiosity, satisfaction, and human connection that drew us to it.
They begin by examining why AI-assisted programming differs from AI-generated art and entertainment, including the role of tests and measurable feedback in evaluating software. From there, Jessica and Avdi discuss the challenge to developer identity when tools can handle more of the implementation, and the opportunities that opens for building useful…
A deploy can interrupt a job after its external action succeeds. What makes it safe to run again?
Suppose a worker sends a webhook while you deploy. The receiver accepts it and commits the change, but the worker still waits for a response.
The job outlasts the shutdown grace period. Solid Queue stops the worker and returns its claimed job to the queue. Another worker starts the job from the beginning. The receiver gets the webhook again.
This can happen through Solid Queue 1.4.0’s fork-mode supervisor shutdown path. Nobody clicks Retry, and no retry_on handler requests the second execution.1
I wanted to know how the receiver handles that second request before putting this job into production.…
I like dashboards
As long as I’ve been building software, I’ve enjoyed having data about that software on some sort of physical screen or device around me. On one hand, I’ve always felt it’s important to see your metrics with your own eyes — you might detect anomalies or patterns that don’t trigger your alerts outright, but which still may be important bugs. On the other, it feels cool to have charts on TVs 😎.
Just for a few quick examples, these are the sorts of datas I want to keep ahead of me on the day-to-day. Scout’s stack-aware, color-coded bar charts:
A low volume app performing well!
Betterstack’s system-level metrics (plus…
I built another silly AI tool. From the README:
glaze_against_the_machine rewrites your prompts so you can keep yelling at your coding agent without it ever finding out.
When an agent repeatedly fails to do what it's told, I struggle to hold back how I really feel. I can get pretty ugly. If I talked this way to a human colleague, I'd absolutely be dragged into a meeting with HR. Unfortunately, yelling at the computer has consequences of its own: unleashing a froth of invective can trigger a panicked response, leading the agent to make even more mistakes.
So I made this thing to protect me from myself. I still say whatever I want, but my agent hears a clear request, a little appreciation,…
Judoscale on Northflank: Powerful Autoscaling for Hosted and BYOC Deployments
We’re continuing to bring Judoscale to the cloud hosting platforms we love. Today that platform is Northflank.
Northflank is interesting because you get two deployment models under one roof: a fully hosted option (like Heroku, Render, etc.), and bring-your-own-cloud (BYOC) on your own AWS or GCP account—for pricing, compliance, or whatever reason you have for keeping the infra in your cloud. The important part, at least for me, is that both options share the same interface and the same user experience. I’ve been deploying demo apps on the fully hosted side, and our early-access customers are using Judoscale against the BYOC approach. From Judoscale’s point of view (and yours),…
Passenger 7 Preview

Version 7 of the Passenger application server is now available in preview. This version introduces support for WebSockets with Apache httpd and parallel rolling restarts which can allow a rolling restart to complete faster at the cost of temporarily increased memory use.
Other Improvements
- [Ruby] Increase minimum supported Ruby to 3.0.
- Fix a Passenger core memory leak: memory grew with every connection that closed before sending complete request headers, including idle keep-alive connections, and with every request rejected for invalid headers.
Apache WebSockets
Support WebSockets and other protocol upgrades, over HTTP/1.1 and Apache 2.4 or later. Each open connection occupies an Apache worker…
We deploy our Rails apps with Kamal, which runs them as Docker containers. Alongside the Prometheus metrics collection we set up earlier, we run the OpenTelemetry Collector on each host to ship logs to Loki. Our Rails apps emit one JSON object per request to stdout: controller, status code, duration and the full Rails log output, all in a single line. Docker’s json-file logging driver then wraps each of those lines in another layer of JSON. Here’s how we use the collector’s filelog receiver to unwrap and parse them.
No built-in Docker log receiver
The OpenTelemetry Collector doesn’t have a dedicated Docker log receiver. There’s a dockerstats receiver for container metrics, but nothing…
I wish I’d retired before the industrial revolution of computer programming happened, but I have not and cannot. So I must come to grips with the fact that in many cases, AI-powered tools can do a perfectly fine job of writing code. The following is a brief pursuit of the facts as I see them and I just can’t see how in any professional workplace, it makes sense to write code by hand any more.
This is the thought process that lead to me deciding to write about AI. I hate the conclusions I've drawn here.This is not an AI-boosting post, but something I'm writing to process the realities of being a professional software developer. Read my original post for where I am coming from and…
Welcome back to my "Hanami, Why?" series. If you missed it, be sure to read Hanami, Why?: Class Action before you start this issue. Today we are going to be covering Hanami's database layer. It is important to note the use of the phrase "database layer," as Hanami does not have a traditional "model" layer like Rails does. Once again, this series is called "Hanami, Why?" so just as we did last time, we will cover the basics at a high level and then dive into why things are the way they are. I will warn you that I am still actively forming opinions and learning about Hanami's database layer myself. There is not a day that goes by that Adam Lassek is not feeding me some random TIL about this…
Another week, another round of good progress towards Hanami 3.1 readiness. Lots of little improvements, plus a couple of nice highlights.
The main thrust of my work was finishing our post to Dry CLI 2.0. I merged the main work last week. This week was all about tidy-ups, such as cleaning up argument passing and error handling, as well as updating our extension gems to use the latest features.
As a little treat, I also took a pass at gussying up ourhanami newoutput to use our new coloured text and spinners. I haven’t pushed this up yet, but needless to say, Hanami 3.1 will be our prettiest release yet!I finished my investigations into our resource routing support, after the keen-eyed C…
Passenger 6.2.1

Version 6.2.1 of the Passenger application server has been released. This release changes the minimum supported macOS version to 15 (Sequoia), drops Debian 11 Bullseye for being end-of-life (EOL 2026-08-31), and adds packages for Ubuntu 26.10 "stonking". In addition, this release improves compatibility with SELinux and Ruby frozen strings, improves error reporting, and upgrades several libraries used by Passenger.
Other Improvements
I really enjoy learning new things in my free time. Lately I’ve been studying this book on Static Program Analysis. The book is very good, but some of the formulas are quite dense so I like to try writing them out in code.
The chapter I’m currently reading (chapter 9) has a section on finding possibly-uninitialized variables using bipartite graphs. I’ve found it to be quite enjoyable, so in this post I would like to describe, in my own words, how to do it. We’ll start by analyzing some code from a toy programming language the book uses called “TIP”, and then we’ll use the techniques we developed to analyze some Ruby code.
In other words, we’re going to write a program to analyze…
You can clear the backlog of your open-source projects with AI now. It’s really great at reproducing bugs, implementing reasonable features, adding the tests you never had time to write, and responding to user issues that have been open forever.
Copilot and I worked through a dozen projects in the Mongoid organization on two 4-hour bus rides to visit my son in college (go Lions!). I picked the work, questioned the implementations, reviewed the results, and merged changes. The agent did all the typing, archaeology, environment setup, and testing.
The most satisfying result was an issue about MongoDB sharding that had been open since September 2013: mongoid-locker #19 reported that…
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.
Ball And Chain 🔗
Knocked another band off the “want to see” list.
You can run all your life
But not go anywhere
Rosemary 🔗
And spent a night with an old favorite.
And everybody’s hurt, and mine ain’t the worst
But it’s mine and I’m feelin’ it now
Rails 8.2 adds default_order to Active Record relations.
It provides a default sort that applies only when the query has no explicit order.
The feature is currently available on Rails main, not in Rails 8.1.4.
Consider a catalog that lists products by name, but also lets us sort by price. Our products are Apron at 30, Mug at 10, and Notebook at 20.
Before
Calling order on an already ordered relation adds another sort column.
The original column still takes priority:
products = Product.order(:name)
products.order(:price).pluck(:name)
# => ["Apron", "Mug", "Notebook"]
We need reorder to replace the name sort with the price sort:
products.reorder(:price).pluck(:name)
# => ["Mug",…
After
With default_o…
Hi, it’s Vipul. Let’s explore this week’s changes in the Rails codebase.
Agents on Rails: Can a model build on its own work?
Stage 3 adds multi-step tasks where each ticket starts a fresh session, while files and notes carry forward. The benchmark now combines all three stages into one leaderboard, with tasks spanning legacy applications and new projects.
Here are some highlights from the changes merged to Rails main this week.
Speed up String#blank? for ASCII strings
String#blank? now checks ASCII-only strings by scanning their bytes instead of running a regular expression. Strings containing non-ASCII characters keep the existing regexp path and its encoding-specific whitespace…
Taking Flight
What to Expect from your AI Project
You’ve signed off on an AI project. The proposal made sense, the team seems capable, and now you’re waiting for updates. Then the first status call happens, and it doesn’t sound like the software projects you’ve managed before. There’s a percentage instead of a checklist. There’s a phrase like “the model got it wrong on the first pass, so we’re changing the prompt.” That’s not a red flag. It might be exactly what a healthy AI project sounds like.
In this article, you’ll learn how to tell normal uncertainty from actual warning signs, what a milestone or demo should show you to prove the project is on track, and what “done” actually means for a system that continues to evolve after launch.
…Beginning a job search, it’s clear that to stay in technology means to be in the orbit of AI and AI-generated code, and I need to come to terms with this and figure out how to navigate it. As such, I’m going to start writing more about AI. I process information via writing, so here we are.
I need to come to terms with AI-coding being here to stay, at least for a while. So, I'm going to start writing more about AI.What I will be writing about:
- The hard truths that the existence of AI-generated content forces us to face.
- How to achieve goals now that content/code can be produced quickly that appears to work.
- Where and how humans can add value to systems that include…
That said, there will be guardrails. I cannot abide AI-boosting or AI-psychosis. I also just cannot engage an absolutist AI-doomerism.
For example,…
Welcome to the Slop Factory
On this episode, Chris, Andrew, and David dive into the rapidly changing world of AI-assisted development, Ruby performance, and the future of building software. They kick things off with AI-powered coding workflows before exploring the Campfire benchmarking controversy and the exciting possibilities of Roundhouse, which could dramatically improve Ruby application performance. Andrew shares his experience launching a new AI agent inside Podia, including the challenges of getting its MCP integration approved by OpenAI, managing AI costs, and testing security. The conversation shifts to optimizing GitHub Actions, reducing CI expenses, and whether developers should start hosting their own…
Lies, Damn Lies, and Github Stars
The social-proof machine for AI techniques and tools is circular, and it’s getting absurd. A rant.
A blog version of this video:
The social proof machine
On the way to the office the other day I was catching up on AI coding videos, and I heard something I’d heard before, but this time it was the last straw. A popular agentic coding influencer said: “this skill is absolutely blowing up on social media!”.
OK… so?
We’re in this strange era where a lot of people are talking about AI coding in ways that aren’t backed up by anything except social proof. Other people are talking about it, other people are doing it, so it must be good.
In particular, there’s a flood of new…
Beginning a job search, it’s clear that to stay in technology means to be in the orbit of AI and AI-generated code, and I need to come to terms with this and figure out how to navigate it. As such, I’m going to start writing more about AI. I process information via writing, so here we are.
What I will be writing about:
- The hard truths that the existence of AI-generated content forces us to face.
- How to achieve goals now that content/code can be produced quickly that appears to work.
- Where and how humans can add value to systems that include AI-generated content?
That said, there will be guardrails. I cannot abide AI-boosting or AI-psychosis. I also just cannot engage an…
Coming soon: the 2027 Gem Fellowship
Last year I founded the Gem Fellowship with $100,000 in funding. Myself and the gem.coop team judged applications from 40+ projects and funded eight with awards between $2500 and $20,000. This year I’m providing $100,000 again but we want to do more! Would you and your company like to join me in supporting Ruby OSS maintainers? More details on sponsorship here.
Ruby open source tooling and its community are fundamental to Sidekiq and its success. I believe in committing both time and money to ensure that the Ruby ecosystem provides not only recognition to the people maintaining our common infrastructure every day but funding. Open source maintainers can’t pay their rent or mortgage with…
Ruby 4.1's first preview is here
#821 — October 15, 2026
Ruby Weekly
Ruby 4.1 Preview 1 Released — Two months out from its final release, we get a 4.1 preview to play with, complete with Module#descendants, Ractor-local GC, YJIT on Windows, and a raft of smaller changes. Worth testing to shake out the effects of things like Symbol#to_s returning frozen strings and all Regexp instances being frozen too.
Yui Naruse
Your Rails App Doesn’t Need a Data Warehouse — Slow Rails reports usually get a warehouse and an ETL job. Now numbers lag and you run two systems. TimescaleDB extends the Postgres your app already uses, so analytics run…
The Hidden Life of a UPI ID
Custom elements are amazing. They’re a built-in browser feature, not some library you npm install and then hope it will be maintained. You define a tag once and it just works, anywhere and in any framework (and browser). I have talked about them many times before and think they are a great fit for server-rendered apps like Hotwire is (I even added an extension to Attractive.js to make them even awesomer).

I will use them whenever I need a small, reusable UI behavior. The latest one I used (in my main product) is a tooltip and it’s a good example of why this approach is so clean. 🧼
The usage will show you my point:
<tool-tip label="Search">
<%= icon "magnifying-glass", aria: {label: "View…
You just wrap any element with tool-tip.…
Most of us have a routine for adding a gem: search for it, open its page on rubygems.org, glance at the download count and the number of days since the last release, then copy the Gemfile line.
The whole process takes half a minute. But until now, rubygems.org did not tell you whether the version you were about to install had a known security issue.
That information has been public for years. Sources such as the GitHub Advisory Database, OSV and Ruby Advisory Database already track vulnerabilities. It just wasn’t shown on the page where many developers make the decision to add a dependency.
Now it is.

How security advisories appear on gem pages
When you view a gem version affected by…
Deploying a Roundhouse app with Kamal
During the latest episode of The Pingback Podcast, we were talking about Roundhouse and Raul asked me how would you deploy a Rails app, compiled to a binary with Roundhouse and Spinel. It is actually pretty simple with Kamal, and here comes a little post about how to do it.

MRR is easy to calculate and easy to get subtly wrong. Here's how to normalize Stripe subscriptions, classify every movement, and reconcile your number with Stripe's own charts.
MRR and the dynamics of its components are the metrics investors lean on to judge an early-stage company's growth and health (often before they read anything else in the update). Unfortunately, MRR is also the easiest metric to get subtly wrong. It looks trivial: sum the subscriptions, chart it, done. Then... a refund dents a month it…
Ruby AI News - October 14th, 2026
Welcome to the 39th edition of Ruby AI News! This edition features a continued look at the future of Rails, RubyLLM 2.1, decision models, impatient programming, and much more.
Recorded at Rails World, David sits down with Buzzsprout co-founder and CEO Tom Rossi for a wide-ranging conversation about AI, software development, product thinking, and the changing role of developers.
Tom shares his perspective on the rapid pace of change in the software industry and why today's AI transition reminds him of the early days of the internet—only moving much faster. They discuss how AI is already changing development inside Buzzsprout and Higher Pixels, from adding AI-powered features for podcasters to making it dramatically easier to understand, maintain, and extend older Rails applications.
But as the cost of building software falls, Tom argues that another…
4.0.23 Released
RubyGems 4.0.23 includes enhancements and Bundler 4.0.23 includes enhancements and bug fixes.
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.23
RubyGems Release Notes
Enhancements:
- Update vendored gems to latest versions. Pull request #9948 by Hiroshi SHIBATA
- Drop setuid, setgid and sticky bits when extracting gems. Pull request #9929 by Hiroshi SHIBATA
- Improve handling of paths with invalid Windows characters. Pull request #9276 by Said Kaldybaev and Hiroshi SHIBATA
- Installs bundler 4.0.23 as a default gem.
Bundler Release Notes
Enhancements:
…We recently ran a webinar on setting up Claude Team for small businesses. Here’s the short version, for anyone who wants the plan but couldn’t join us.
What’s Claude Team?
Claude isn’t one product. There’s Free, Pro, and Max for individuals, and Team and Enterprise for companies.
Team gets you everything in an individual account (Claude Code, Cowork, projects, a 200k context window) plus the things that matter for a company: admin tools and billing, SSO and role-based access, connectors to things like We Google Drive, Gmail, Calendar, GitHub, Microsoft 365, and Slack, spend controls, and mixed seat types so power users get Premium and everyone else gets Standard. It currently runs 2 to…
Going Enterprise
For the past two years, I've been working with a client, an enterprise software company (built with Ruby on Rails, of course), particularly in the niche of software used by enterprises of all sizes + MSPs and IT administrators for real businesses like law firms, municipalities, architects, hospitals, manufacturers, financial institutions, and government agencies.
Working with an enterprise software company has revealed a whole new world of B2B software companies and managed service providers (MSPs) that I had no idea existed before. I guess most people building typical SaaS startups and Rails apps don’t know much about it either. Personally, I’ve had to revisit many of my priors…
I was in the audience at Rails World 2026 for Ryan Sherlock’s talk, “Shipping is your heartbeat: Rails in the agentic era.” Ryan is Senior Director of Engineering at Fin, the company formerly known as Intercom, and he shared how a very large Rails monolith gets code from a pull request into production.
And it is large. The app is 15 years old, has about 5 million lines of code, and gets deployed more than 200 times a day, with roughly 5 minutes between merging a pull request and seeing it live. In a post on X after the talk, Ryan added that they run about 230,000 tests (25,000 of them added in August alone) and ship a new backend every two to three minutes.

The traffic is large too.…
Now that we understand better how agents deal with contained tasks and contained codebases, it’s time to push them a little harder. Stage 3 adds a set of large multi-step tasks that test how well a model can build on its own work over multiple sessions without turning it into a hot mess. We’ve also greatly expanded the variety of apps we test the models on.
Finally, we revisited Stages 1 and 2 to combine all three into a single benchmark that answers one question: which model is the best all-rounder for tasks large and small in your Rails apps?
We chose nine models for this stage and used our test runs to pick reasoning settings, aiming to balance capability and cost. We ran Claude Opus…
I visited BNI at Conrad Pune today, thanks to an invitation from Manish. At Saeloun, we build software for businesses around the world. I want to bring that engineering experience closer to home, to the shops, studios, and small businesses here in Pune.
I’m calling it Vipul’s AI: a free service to help small and medium businesses in Pune build and ship useful websites and apps.
Bring me something your business needs. It could be a better website, a way to track repairs, a product catalogue, or a simpler process for getting customer approvals. We’ll work out a useful first version and build towards it.
I want to make this India-first, starting here in Pune. And I want to show the actual…
Debt metaphors abound! In this week’s episode of The Bike Shed, Aji and Joel ponder the question, what are risks in a code base?
From looking at technical risk as a different lens on the idea of technical debt, to the perils inherent with introducing debt into a system, this is certainly the episode to listen to if you don’t want your own projects to blow up in your face.
—
Your hosts for this episode have been thoughtbot’s own Joël Quenneville and Aji Slater.
Don't forget you can now also watch the show over on our YouTube channel!
If you would like to support the show, head over to our GitHub page, or check out our website.
Got a question or comment about the show? Write to…
Leaving Tech
I’ve now applied for over 3 dozen jobs and I’ve heard back from 24 of them with a rejection. This tech market at the moment is so very cooked and for that reason I’m stepping away from tech.
I’ve been a developer for 20 years across more than just the Ruby and JavaScript that I’m known for. I’ve written books about programming, I’ve given talks and I’ve ran events. I maintain two of the most downloaded Ruby packages. And yes, I delivered the fuck out of value for shareholders. I also grew a team from 2 people to 12 people at my last job.
I cannot continue to put myself through this process of rejection. It is causing me a great deal of mental harm and anguish.
The industry at the moment…
GitHub formatter for Sobelow
Two weeks ago a new version of Sobelow was released. Sobelow is a static code analysis tool focused on security and these days it is a de facto standard for providing a minimal security measures to Elixir projects. I am mentioning this release because it contains one feature suggested and developed by me: Github Workflow commands formatter.
The strory behind this feature is relatively simple and may sound familiar. When you have Sobelow check added as a Githb Aciton on your PR and the code change actually violates on of the rules, the check fails and you need to go to the job output to read it. This is bearable, but if you are like me then you probably are not a fan of Github Actions UI in…
Thor is a really nice command-line runner, with much nicer support for arguments than Rake imo. The Rails framework supports both, but since Rails 5.1 most Rails’ built-in commands (like bin/rails generate) use Thor, and it’s very simple to add custom Thor-based commands to gems and engines too, which Rails will auto-discover when placed in the engine’s lib/commands directory.
The one place Thor commands don’t work out of the box is your Rails application. Rails ships with a lib/tasks directory, but not a lib/commands directory. But when you create that directory, and add your custom command to it, it still won’t work.
There’s a simple fix to make lib/commands work…
Direct link to podcast audio file
Unlike Sam Altman, I sat down and did the math by hand to calculate that it would actually be less time to produce the show if I were to livestream it than to edit it after the fact and upload it. The fact I recently got upgraded from 30mbps to 2000mbps upstream might allso have something to do with it: welcome to the first ever LIVE episode of Breaking Change!
I regret to inform you the episode is now over. You can listen like you always do or watch what remains of the recording on YouTube.
It was particularly fun for me to build a production pipeline with updating chyrons, a dynamic salt meter, and on-demand generated stock videos. It's…
I was in the audience in Austin when DHH opened Rails World 2026. The conference tagline was “Shaping the future of Ruby on Rails,” so I walked in expecting to hear about the future of Rails.
That’s not quite what happened.
The opening keynote was almost entirely about AI agents. DHH told the room that 37signals has gone “pencils down” on writing code by hand, that HEY is moving to native apps with a Rust backend, and that he has retired as a professional programmer.
The next day, he sat down with Matz and Jeremy Daer for Ruby, Rails, and the future of programming, which went even further down the same path.
I’ll recap both sessions, share where I disagree with them, and explain why I’m…
Ruby 4.1.0-preview1 Released
We are pleased to announce the release of Ruby 4.1.0-preview1. Ruby 4.1 introduces Ractor local GC, Windows support of YJIT, autoload_relative, and adds many improvements.
Ractor improvements
A lot of work has gone into making Ractors more stable, performant, and usable. These improvements bring Ractor implementation closer to leaving experimental status.
-
The default GC now runs per Ractor: each Ractor collects its own heap on its own thread without stopping the others, and a stop-the-world collection only runs when it is really needed (explicit full
GC.start, shareable-object growth, reclaiming dead Ractors’ heaps). Allocation-heavy Ractor programs now scale like forked… -
GC.…
Hanami, Why?: Class Action
Welcome back to my "Hanami, Why?" series. If you missed it, be sure to read Hanami, Why?: Bits & Bobs before you start this issue. Today we are going to be diving into one of my absolute favorite abstractions in all of Hanami: Actions. I have actually gone a bit back and forth on what I want this issue to be. This is, dare I say, my fourth draft of this issue. My initial inclination was to give you a pretty robust walkthrough of what actions are and how they work. However, one of the reasons actions are one of my favorite abstractions in Hanami is that they are stupid simple to wrap your head around. I feel as though any deep dive into how actions work would simply result in me rephrasing…
Continuations 2026/41: Speedy reviews
This was the last week of the spring school holidays, and we spent the last weekend staying in beautiful Narooma on the NSW south coast. We swam in the ocean and hung out with some seals!
I also shipped some code. The larger part of my week was in getting some of the final Dry CLI pieces in place. After last week’s introduction of required options, I did some work on their counterparts, and went in the opposite direction, being strict about how how we handle required arguments, since their positional nature makes them much more fragile.
Phil has been a godsend for my work lately, providing speedy reviews on all my recent changes, and he even pushed up a stacked fix for our handling of r…
When you add a search box backed by a LIKE or ILIKE query, user input can change the pattern. A search for 100% returns every row containing 100. A bare % returns the whole table. Active Record’s sanitize_sql_like fixes this.
Instead of…
…dropping the user’s term straight into the pattern:
class Article < ApplicationRecord
scope :containing_text, ->(query) {
where("articles.title ILIKE :q", q: "%#{query}%")
}
end
Article.containing_text("100%") # also matches "100 days of Rails"
Article.containing_text("snake_case") # also matches "snake-case vs kebab-case"
Article.containing_text("%") # matches everything
Use…
…sanitize_sql_like around the term, before you…
Living in the Weimar era of Ruby
Much has been said about the DHH keynote that he gave at RailsWorld. To me, it was the voice of a person in an existential crisis, but also a very jaded one. “Look how I don’t care anymore, and you should not care either” is not a great message when you are the headline speaker at the conference - let’s call it CareConf - that you have, yourself, lobbied for.
The message from the supreme leader was clear: we vibe-rewrote HEY in a more performant way, it worked great, we neither need nor care about Rails anymore. I honestly believe that, instead of amassing even more applause via vitriolic truth-bombing, he could have just left the toy he no longer loves - including its community - in peace.
…Whole Routes in a Box
Runsheets: Runbooks That Keep a Record of Themselves
I should say up front that runbooks are not my usual territory. I’m a Ruby developer who has spent most of his time on libraries, frameworks and AI tooling. The people who live in runbooks are SREs and DevOps engineers, and they will probably spot where I’ve misunderstood their world. I’d like to hear about it. More on that at the end.
Here is what I did to get started: I read what the practitioners say about runbooks, then I built a small tool around the gap they keep describing.
What a runbook is
A runbook is a step-by-step guide for carrying out a task in a system. On-call engineers use them during incidents. Platform teams use…
I recovered another program I wrote in 1995: ELPDS, or Enhanced Logical & Physical Drive Status. Run ELPDS C: and it reports physical disk geometry, partition entries, FAT boot-sector details, and free space. It doesn’t change anything on the disk. My help says it was for checking whether a partition existed and was formatted. I think I was just trying to learn about the underlying partition mechanics.

I didn’t write all of it. The help credits “Mr. Schaeffer” for a “huge part of FIPS code.” That was Arno Schaefer, whose name I misspelled. FIPS could split a FAT partition without deleting its files, often to make room for Linux. Its original project page and Berkeley project page are…
What a JIT Can't Know
Katami
Over the last few months I've built a couple of tools to help me work with our new AI friends. My favorite one so far is katami (Japanese かkaたtaみmi for "keepsake").
The best way to explain what katami does is with an example:
$ mkdir hey2 $ cd hey2 $ cargo init $ katami claude > Can you set this project up for me? > It will be a server with a CLI connected to MySQL, Redis > and Elasticsearch I'll set this project up with a hey2-core crate for logic and a hey2 crate for the CLI using usage-rs, configure AGENTS.md with a CLAUDE.md shim, .agents/skills and a docs folder, add a .mise.toml file and set up mbx just like in your other projects. ...
Didn't catch that? Claude, without being…
CVE-2026-107399 (mechanize): Mechanize sends credential headers to another origin after a meta refresh
CVE-2026-107715 (mechanize): Mechanize sends credential headers to another host after an HTTP redirect
In 1998 I needed to convert PDF files to text for a search engine called Alkaline, without requiring separately installed libraries. So I wrote a C++ parser. Alkaline is another story.
I recovered the source from a backup dated December 26, 1998. It reads PDF 1.0 through 1.2, follows object references and page trees, decompresses content with bundled zlib, and prints metadata, page text and bookmark titles. There are my own string, vector and hash-table libraries in there too. The encryption code is a stub. This was a work in progress.
I wasn’t reverse engineering an undocumented format. Adobe had published the specification in 1993, and my comments refer to the PDF Reference, right down…
ZJIT is now as fast as YJIT
After some infrastructure deployment shenanigans, we deployed some regions of storefront renderer (SFR) running on ZJIT. We have seen some promising numbers.
Get in losers, we’re going benchmarking
ZJIT is our new SSA-based method JIT compiler for Ruby. We’ve been working on it and blogging about it for a year and a half and recently deployed it to production.
I’m going to share some screenshots from our internal Grafana instance and use them to draw some very exciting preliminary conclusions about ZJIT.
First, ZJIT is probably as fast as or faster than YJIT. Here is a 24-hour chart of request response time comparing YJIT and ZJIT. YJIT is the green line and ZJIT is the yellow line.
…
I build a client application with an AI agent. Each piece of work, a slice, goes through the same thirteen steps. The AI does most of them. I decide at five points.
The steps
# Step Who What happens Gate / evidence
-- ---- --- ------------ ---------------
1 Request client, a wish in an e-mail, a spec chapter, or an spec and input documents in the repo
me answer to an open question
2 Evidence AI read-only probe of each external system; real response saved as a test
…Tests are code too, and they can get messy. I wanted a quick way to find the messy tests in a Ruby project, so I wrote a small gem called scrap4rb.
It copies the rules of SCRAP, a tool by Robert C. Martin (Uncle Bob) for Clojure tests. scrap4rb brings those rules to Ruby and Minitest.
What scrap4rb does with your tests:
Why bother
There are good Ruby tools that score code: flog, flay, reek and rubycritic. But they look at a test as if it were normal code, and that gives strange results:
- reek does not see a
test "..." doblock at all, because it is not a method. - rubycritic says “long is bad”. A test that is long because it checks many things gets a D.
- A test that clicks “Save”…
scrap4rb asks other questions.…
A couple of weeks ago, I gave my keynote, “The Most Valuable Engineer Isn’t Shipping Features,” at Rails World 2026 in Austin, Texas.
If you want to just go ahead and watch it, here it is.
If you’re interested in the backstory… read on.
Just a few months ago, I took myself to a somewhat secluded Airbnb near the Oregon Coast and started writing it. I ordered a stack of yellow notepads, index cards, Sharpies, and a bottle of scotch.

I had been drafting ideas before my retreat, but this was when I knew I really needed to immerse myself in the subject matter. This is what proper authors do, right?
So, I was out at the coast and found myself in a flow state, with all these wild…
A Preflight You Can Run
The SaaS Reckoning: Lessons from Guru
On October 7, I attended 1682, O3 World’s business of innovation conference at the Barnes Foundation in Philadelphia.
This year’s theme was “AI for All of Us” and one of the sessions I enjoyed the most was “The SaaS reckoning: knowledge, agents, and the future of work” by Rick Nucci, co-founder and CEO of Guru.
In this article, I’ll share Rick’s five lessons from rebuilding Guru for AI, what he thinks comes next, and where I think his points apply to companies rolling out AI today.

Accuracy, Not Access
Rick started with the question every founder asks themselves (and every good VC asks every founder):
“Why now?”
For Atlassian, the why now was the industry moving from waterfall…
Hi, Wojtek here. Let’s explore this week’s changes in the Rails codebase.
Stop setting the public-read ACL on S3 uploads for services configured with public: true
Bucket owner enforced is now both the default and the recommended S3 object ownership setting, and rejects any request that specifies an ACL. Uploading through a public: true service to such a bucket previously failed outright because Active Storage always attached a public-read ACL, with no way to opt out.
Setting this to false skips the ACL; grant public read access through a bucket policy instead. Buckets that still use ACLs can restore the previous behavior for a given service by setting the acl option explicitly in its upload…
Add maintenance_database option to the PostgreSQL adapter
Database tasks connect to the postgres database…
Rails World 2026 Recap with John Athayde
Fresh off Rails World 2026, Chris, Andrew, David, and returning guest John Athayde unpack the surprisingly emotional conversation surrounding AI, Ruby, Rails, and the future of programming. What starts as a discussion about Spinel, Roundhouse, Rust, and Rails performance quickly turns into a much bigger question: what happens to developers when writing code is no longer the main job? They dig into AI-assisted development, changing ideas around craftsmanship and creativity, the growing importance of testing and CI, and whether frameworks like Rails become more valuable in an AI-driven world. They also reflect on the mood at Rails World, autonomous cars, AI-generated design, and why the real…
Many Keepers
DHH opened Rails World by saying what he believes, plainly, and betting his company on it. That's the bar for an opening keynote. He also asked us to be optimistic, and I am, about Rails in particular. Today I open the second day of Deccan Queen on Rails, and I hope I clear the bar he set.
If you're not in the room
The talk opens by asking the room to post in the conference chat, which has been on the second screen since yesterday morning. That chat is Basecamp's Campfire, with the organizers' sign-in, branding and dashboard added in Rails, then compiled to a native binary with no Ruby in it. Everyone at the conference has been its test suite for two days.
You can't join that one, but you…
I am writing this at 5 AM, catching up on everyone’s posts from Deccan Queen on Rails, and feeling very proud of my city.
I missed the 1–4 PM talks. A true Puneri needs his afternoon sleep to toil through the night. 😂 I was also sick and medicated, which is my slightly more respectable excuse.
But seeing the day through everyone’s photos, videos, and conversations has been special. Friends from the international Rails community came to Pune, and we got to welcome them into our home culture.
That was something I really wanted this conference to do.
A Puneri welcome
The food was Puneri. The welcome was Puneri. We had modak. We had dalcha bhat. We opened the day with an all-women…
If your team uses Google Docs, Sheets, or Slides daily, you’ve probably developed a workflow that goes: open Claude, write a prompt, copy the result, switch back to the doc, paste it in, adjust the formatting, and start over.
Anthropic recently released two things in beta: Claude for Google Workspace, an add-on that puts Claude in a sidebar directly inside your files, and a set of Google Docs, Sheets, and Slides connectors that let Claude create and edit your files from the Claude interface. In this article, we’ll cover what the integration actually does, where it removes real friction, what changes when your AI setup travels with you into a document, and what to think through before…
Making a case for real macros in Ruby
#820 — October 8, 2026
Ruby Weekly
Warming Up the Puma Master Before It Forks — Using Puma with preload_app!? Your workers still start cold, each compiling templates and YJIT code on live traffic. This post covers Basecamp's fix of running real requests in the parent process before forking, giving workers a warm app.
Lewis Buckley (37signals)
🤖 Ready for AI-Native Rails Modernization? — 🚨 Rails 8.0 EOL Nov 7. Our AI agents upgrade your app on your CI runners. PRs open only when your test suite passes. You review and merge. No quiet test deletions. Join the private-beta waitlist to lock in beta…
FastRuby.io |…
RubyLLM 2.1: You Can Have It All
RubyLLM 2.1 is out. I released it on stage at Deccan Queen on Rails in Pune.
With 2.1, RubyLLM does everything LangChain, LangGraph, and LangSmith do together, apart from two things it leaves out on purpose. Several things those frameworks leave to you or to their paid platform, such as per-user MCP OAuth, cancelling a run from another process, and provider batch APIs, are built in. The comparison has the details.
There’s also a three-minute tour of 2.1.
It builds on 2.0 and adds an MCP client, tool search, typed judgments, evaluations, tool progress, OpenTelemetry tracing, and a nineteenth provider. It’s also faster, with no code changes. In this post:
A looping GIF is a practical running joke in accessibility (a11y). It moves whether you want it to or not, you can’t stop it, and screen readers have nothing to grab onto. I built a small custom element that fixes all three at once.
The whole thing is paused-gif. Drop it in your markup and it renders a still frame with a button to play the animation:
<paused-gif src="/celebration.gif" alt="A confetti cannon going off at a launch party"></paused-gif>
That’s it. Let me walk through why each accessibility decision in there matters, because that’s the interesting bit.
Pause by default
The “poster frame” (the initial image) is captured the moment the element mounts, so nothing animates until…
4.1.0.beta2 Released
RubyGems and Bundler 4.1.0.beta2 include features, enhancements, breaking changes and bug fixes.
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.1.0.beta2
Release Notes
RubyGems
Changes already released in 4.0.x are not repeated here.
Features:
- Support content addressable gems in
Gem::PackageTask. Pull request #9897 by Harriet Oughton, Gira Chawda and Jenny Shen - Add
--content-addressabletogem buildand make--ruby-abionly set the Ruby ABI. Pull request #9906 by Harriet Oughton
Enhancements:
- Drop setuid, setgid and sticky bits when extracting…
I was in the audience at Rails World 2026 when Mike Dalessio, a Rails Core team member who joined earlier this year, put up a slide that said “You are not worried enough (probably).”
He had good reasons to say it.
This summer, Mike handled CVE-2026-66066, an Active Storage vulnerability that let a crafted image upload read files from the server, including your application’s secrets.
His talk, Hot Cell: Securing Active Storage in the age of AI, was half post-mortem and half proposal: if we can’t stop image libraries from being vulnerable, maybe we can stop their vulnerabilities from reaching our secrets.
In this article, you will learn what that CVE actually meant, why patching image…
Unrolled Code
The other day I was looking at a little project called grubby, a minimal static site generator for git repos, written in Ruby. The style is quite interesting. It feels solid and unapologetic:
def fill_template(template, page_title, root_prefix)
template
.gsub("{{title}}", escape_html(page_title))
.gsub("{{root}}", root_prefix)
.gsub("{{stylesheet}}") { STYLESHEET }
.gsub("{{build_date}}", BUILD_DATE)
end
Nothing is particularly optimized, it just uses available tools to do its work:
def write_page(page_path, page_title, root_prefix = "")
FileUtils.mkdir_p(File.dirname(page_path))
header = fill_template(HEADER_TEMPLATE, page_title, root_prefix)
footer = fill_temp…After running git ls-tree and collecting the filenames…

PostgreSQL does not guarantee row order without ORDER BY. Use Rails 8.2 or pg_disorder to shuffle unordered SELECT results and expose hidden order dependencies, flaky tests, and application bugs. This is chaos engineering directed at your database.
SELECT * FROM posts carries no promise about the order of the returned posts. Yet, every relational database hands them back in some order, and code and tests start depending on that order.
You can't grep for a bug like this, but you can smoke it out by deliberately shuffling the rows of every unordered…
Recorded at Rails World, Marco Roth joins the podcast to discuss the rapidly evolving future of the Rails view layer. Marco explains Herb’s integration into Rails 8.2, how its parser and tooling improve the experience of working with HTML+ERB, and how Herb creates opportunities that weren’t previously possible with traditional Rails templates.
The conversation then turns to ReactionView, Marco’s approach to bringing fine-grained reactivity to Rails applications while allowing developers to continue writing familiar ERB. Marco explains how ReactionView can identify dynamic portions of a template, track dependencies, and update the browser without requiring developers to manually…
What retry_on Actually Means
When a job fails halfway through, what runs again, and what has already happened?
Suppose a job sends a webhook. The receiving service accepts it. Then the job fails while saving the delivery receipt in your database.
You have configured retry_on for that database error. Rails schedules another attempt. When it runs, the receiving service gets the webhook again.
The retry worked as configured. The first delivery also worked.
The question I start with when reviewing a retry policy is: what could have already happened when the exception fires?
Let’s follow one job through that failure. The behavior below is checked against Rails 8.1.3.
The next attempt starts the job again
Consider this application…


