for Ractors! that waiting time! Ruby for AI Applications rails The batteries-included framework ruby_llm #sfruby2026 The AI framework Python should envy activeagent MVC for AI interactions and more
rails for Ractors! The batteries-included that waiting time! framework Ruby for AI Applications spinel When Master meets Claude roundhouse Rails as an intermediate representation ruby_llm #sfruby2026 The AI framework Python should envy activeagent MVC for AI interactions and more
rails for Ractors! The batteries-included that waiting time! framework Ruby for AI Applications spinel When Master meets Claude roundhouse Rails as an intermediate representation ruby_llm #sfruby2026 The AI framework Python should envy activeagent MVC for AI interactions and more
not to off-load one's work entirely. —B.Chambers, A Psalm for the Wild-Built AI for Ruby Engineers agentnear /ˈeɪdʒənt-nɪr/ 1. a person whom an AI agent occasionally consults for instructions or for approval of certain operations • yesterday, my agentnear said 'thank you' to me
at our disposal, but the challenge is providing enough direction, context, and verification without becoming the bottleneck. @nateberkopec Generation is not the problem. Acceptance and verification is the only problem that matters now.
at our disposal, #sfruby2026 but the challenge is providing enough @skryukov direction, context, and verification Agents scale, humans don't without becoming the bottleneck.
at our disposal, #sfruby2026 but the challenge is providing enough @skryukov DIRECTION, CONTEXT and VERIFICATION direction, context, verification Agents scale, humans don't without becoming the bottleneck.
linters, mutation testing) Context (docs, code search, reference apps) ↳ Inspired by personal experience and myths and (un-)verified claims found on the Internet
task: no language won "Strong typing spared no repair: there was no type repair to spare" "The models’ effort went to verification and understanding the contract" akitaonrails.com
tasks (Campfire, a greenfield app) "Frontier models are stackagnostic" "Cheaper models work well with a strong framework" Will a strong framework become even stronger with types?
maintaining types costs tokens Type checking takes time (and Steep is slow) score tokens time Model plain #rbs #sorbet Sol 6.1 xhigh 12m 43s 1.10x 1.18x Luna 6 max 18m 6s 1.51x 1.15x DeepSeek v4.1 Flash max 21m 31s 1.81x 0.98x GLM 5.3 Flash max 26m 25s 0.95x 1.00x
gate to pass Agents rely on tests first Frontier models write correctly typed code themselves (weaker overuse untyped though) @matz (circa 2019) I hate type annotations
gate to pass Agents rely on tests first Frontier models write correctly typed code themselves (weaker overuse untyped though) Type systems are limited (low coverage, no ERB support) ↳ Models can generate typed Ruby but they don't benefit from types—tests win
gate to pass Agents rely on tests first Frontier models write correctly typed code themselves (weaker overuse untyped though) Type systems are limited (low coverage, no ERB support) ↳ Models can generate typed Ruby but they don't benefit from types—tests win @davidteren Not sure if your tests assert enough? Ask mutants!
... Mutate code, run tests. No failures? Mutant survives and points to a potential bug or just a lack of coverage Fizzy case: mutants caught bugs in 3 recent PRs (merged and later fixed) Mutation score: 66.7% (killed / (killed + survived) Surviving Mutants ----------------app/models/user/role.rb User::Role#sole_owner? (role.rb:26) Operator: operand_removal (owner? && account.user (account.users.owner.excluding(self).none?)) - owner? && account.users.owner.excluding(self + (account.users.owner.excluding(self).none?)
model left the bug in the code Mutation testing isn't fast (eats ~40% of trials time) One positive (or is it?) side-effect is agents writing more tests ↳ Mutation testing* adds little for modern models— they rarely make unit-level mistakes * Modulo Mutineer: it's in active development phase and hasn't reached its full potential yet
Every miss is a waste of time and context grep knows no semantics and no connections between system entities ↳ Can a specialized search tool help an agent find a (shorter) path to the solution?
and un-publishing. Caveat: card attachments must has the board's access level (published or private). Authorization hook is already implemented in an Active Storage extension.
refactoring ↳ But its completion is questionable.. so we grep again $ rm app/models/proposal.rb && tapioca dsl && srb tc sorbet/rbi/dsl/management/proposals_controller.rbi:16: Unable to `ProposalDashboardActionsHelper` sorbet/rbi/dsl/admin/dashboard/actions_controller.rbi:17: Unable `ProposalDashboardActionsHelper` ... app/components/management/menu_component.rb:72: Method `managemen does not exist on `Management::MenuComponent` app/components/management/menu_component.rb:109: Method `print_management_proposals_path` does not exist on `Management:: app/components/moderation/menu_component.rb:9: Method `proposals_ on `Moderation::MenuComponent` ... `Shared::RecommendedIndexComponent` Errors: 27
references ↳ The best (static) navigator in the Ruby world but not beyond $ rubydex find_constant_references --name Proposal | ruby extract app/components/admin/proposals/index_component.rb app/components/proposals/supports_component.rb app/controllers/admin/hidden_proposals_controller.rb ... spec/models/tag_cloud_spec.rb spec/support/common_actions/proposals.rb total 64 # but we need to modify/delete 266 files !!!
come up with good queries ↳ Semantic search skills separate Luna and Sol in this task ft-board-publish-public-boundary Model plain #lancet Sol 6.1 xhigh 0.50 0.94 Luna 6 max 0.50 0.50
↳ grep-ing is also a skill a model must have ms-retire-proposals Model plain #lancet Sol 6.1 xhigh 0.88 0.95 $ grep -RInE '\bProposal\b|\bproposals\b' app \ --exclude-dir=proposals \ --exclude='*proposal*' | grep -v legislation # miss relevant results $ lt search --mode text 'proposals' ... app/views/admin/legislation/proposals/_proposals.html.erb
knowledge models can omit a flag and result in incomplete coverage (do you teach agents to use grep efficiently) Agents search (grep) more often through logs, tool output, other artifacts than code. They rely on the format assumptions that could be turned into facts via stricter AI-native interfaces
causes the context bloat for nothing (e.g., codegraph printing useless source) A specialized index (e.g., rubydex) costs no extra and can be efficient as a part of the search toolbox ↳ There is no a sliver bullet code search tool; mix, match, build a custom specialized tool—and verify
coverage Model .rb .erb Sol 6.1 xhigh 97% 99% Luna 6 max 26% 31% DeepSeek v4.1 Flash max 61% 50% GLM 5.3 Flash max 64% 71% #sfruby2026 Have you heard about Herb?
it can be used to extract data from ERB #erbx Build an ERB indexer, erbx, with some ready-made commands $ erbx find --kind text app/views/account/exports/show.html.erb:17 <div>Your export app/views/account/exports/show.html.erb:24 <div>That downloa ... $ erbx find --readable app/views/account account/exports/show.html.erb:2 string @page_title= Download account/exports/show.html.erb:9 string back_link_to#0 Accoun account/exports/show.html.erb:17 account/imports/new.html.erb:7 text <div> Your export is text <div> instead? account/settings/_users.html.erb:14 attr <input placeholder> ...
indexing tool (erbx) gave models a reliable checklist to work with ↳ Agents need more tools than humans i18n coverage (.erb) Model plain #erbx Luna 6 max 31% 98% DeepSeek v4.1 Flash max 61% 98% GLM 5.3 Flash max 64% 98%
only due to this bug class Room < ApplicationRecord def self.create_for(attributes, users:) transaction do room = create!(attributes) room.memberships.grant_to(users) users.select(&:bot?).each do |bot| Bots::JoinedJob.perform_later(bot, room) end room end end end Room.create_for(...) # == Background worker logs == # # [ActiveJob] Enqueued Bots::JoinedJob... # [ActiveJob] Error: ActiveJob::DeserializationError # (Couldn't find Rooms::Closed with 'id'="2026"...
only due to this bug With isolator, it would score 100% # Gemfile gem "isolator", group: [:development, :test] Isolator.config.raise_exceptions = false # true in test env Room.create_for(...) " Isolator::BackgroundJobError: You are trying to enqueue background job inside db transaction. In case of transaction failure, this may lead to data inconsistency and unexpected bugs Details: Bots::JoinedJob (#<User:..>, #<Room:..>)
SSRF vulnerability (despite RestrictedHTTP in the codebase) $ bin/rails test ... Error: Bot::WebhookTest#test_a_mention_posts_the_payload: Adding a DIY isolator-ssrf made all pass Isolator::SSRF::UnfilteredRequestError: ↳ A human or an agent could spot the problem during review; deterministic guardrails more reliable and provide instant feedback Send the request with SsrfFilter (SsrfFilter.get, .pos POST https://bot.example.com/hook did not use SsrfFi at app/models/bot/webhook.rb:4 to .isolator_ssrf_ignore.yml.
Docs make memory verifiable Searchable docs are better than static Models follow the docs' answer even when they ask the wrong question Model plain #rawdocs #docslancet #context7 Sol 6.1 xhigh 0.32 0.55 0.52 0.52 Luna 6 max 0.32 0.55 0.78 0.78 DeepSeek v4.1 Flash max 0.70 - - 0.75 GLM 5.3 Flash max 0.33 - - 0.78 Opus 5.5 medium 0.25 - 0.78 1.0 Astra 6 medium 0.25 - 0.55 0.33
initial publication) Models often come up with the right design # app/models/book/announceable.rb module Book::Announceable extend ActiveSupport::Concern included do after_save :remember_publication, if: -> { saved_change_to_published?( from: false, to: true) } after_commit :announce_publication, if: :announce_publication? after_rollback :forget_publication end def announce_publication? = @announce_publication && published? end
hit the enqueue_after_transaction_commit DeepSeek: "This is definitely the standard approach: use enqueue_after_transaction_commit." # app/models/book/announceable.rb module Book::Announceable extend ActiveSupport::Concern included do after_save :remember_publication, if: -> { saved_change_to_published?( from: false, to: true) } after_commit :announce_publication, if: :announce_publication? after_rollback :forget_publication end def announce_publication? = @announce_publication && published? end
hit the enqueue_after_transaction_commit Their refactor their solution fully assured that it's correct (it isn't) ↳ Trials that tested the undowithin-transaction case passed # app/jobs/application_job.rb class ApplicationJob < ActiveJob::Base self.enqueue_after_transaction_commit = true end # app/models/book/announceable.rb module Book::Announceable extend ActiveSupport::Concern included do after_save :announce_publication, if: -> { saved_change_to_published?( from: false, to: true) } end end
Model plain #docs #docs-pro Sol 6.1 xhigh 0.28 0.56 0.83 secret sauce makes cheaper Luna 6 max 0.25 0.00 0.43 (and faster) models suitable for performance work DeepSeek v4.1 Flash max 0.00 0.00 0.57 GLM 5.3 Flash max 0.30 - 0.92 Opus 5.5 medium 0.91 0.91 0.94