Sorbet
Static type checker for Ruby — adds gradual typing to Ruby using T:: annotations and sig{} method signatures. Sorbet features: T.let(), T.must(), T::Sig, sig { params(x: String).returns(Integer) } method signatures, T.nilable() for nullable types, T::Struct for typed value objects, T::Enum for enums, RBI files for third-party type stubs, Tapioca for auto-generating RBIs from gems, runtime type checking in development (T::Configuration.call_validation_error_handler), strictness levels (# typed: false/true/strict/strong), and IDE integration via Spoom. Created at Stripe and open-sourced. Alternative to Steep/RBS for Ruby type checking. Highly performant incremental type checking via C++ implementation.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Static analysis tool — no network security concerns. Sorbet type checking can catch type confusion bugs in agent code that could be exploited. T::Struct const attributes prevent mutation of agent configuration objects. Local CLI tool, no external data transmission.
⚡ Reliability
Best When
Your Ruby agent service codebase is large enough that type errors are a recurring problem and you want IDE autocompletion with type safety — Sorbet provides Stripe-tested production-grade Ruby typing.
Avoid When
Your codebase is small, you're prototyping, your team is unfamiliar with typed Ruby, or you have heavy metaprogramming that resists static analysis.
Use Cases
- • Typed agent service signatures — sig { params(agent_id: String, options: T::Hash[Symbol, T.untyped]).returns(T.nilable(Agent)) } annotates agent service methods; Sorbet catches type errors before runtime in agent codebase
- • Gradual agent codebase typing — # typed: false on legacy agent files, # typed: true on new files; incrementally add type coverage to agent Rails app without requiring 100% coverage upfront
- • Agent config typed struct — class AgentConfig < T::Struct { const :model, String; const :max_tokens, Integer; prop :temperature, Float, default: 0.7 } — typed immutable agent configuration object with Sorbet enforcement
- • T.must() for agent nil safety — agent = T.must(Agent.find_by(id: id)) asserts non-nil at runtime; Sorbet's flow-sensitive typing narrows type after T.must() call; eliminates NoMethodError on nil in agent service critical paths
- • Tapioca for agent gem RBIs — bundle exec tapioca gems generates RBI type stubs for all Gemfile gems; agent Rails app gets type information for ActiveRecord, Sidekiq, HTTParty without manual RBI authoring
Not For
- • Quick scripts and tooling — Sorbet type annotation overhead is not worth it for one-off agent scripts; use for production agent service code only
- • RBS/Steep users — Sorbet and Steep/RBS are competing Ruby type systems; don't mix; choose one approach for agent project type checking
- • Dynamic metaprogramming-heavy code — Sorbet struggles with Ruby DSLs that heavily use method_missing, define_method, and dynamic dispatch; agent code using Rails concerns, Grape DSL, or Pundit may require many # typed: ignore workarounds
Interface
Authentication
No auth — local static analysis tool.
Pricing
Sorbet is Apache 2.0 licensed, open-sourced by Stripe. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ # typed: true strictness level required for sig{} checking — # typed: false files skip all type checking; # typed: true enables method signature checking; # typed: strict requires signatures on all methods; agent files left at # typed: false get no benefit from added sig{} annotations; set minimum # typed: true for new agent service files
- ⚠ Rails dynamic methods require RBI stubs — ActiveRecord scope, attribute, has_many generate methods Sorbet can't see; without tapioca-generated RBIs, agent.name causes 'Method name does not exist on Agent' errors; run bundle exec tapioca dsl after every Rails model change to regenerate agent model RBIs
- ⚠ T.nilable() vs T.must() interaction — T.nilable(Agent) type requires nil check before calling methods; Sorbet flow-typing narrows after if agent; agent code using &. safe navigation instead of if-nil-check doesn't narrow type; Sorbet still requires T.must() or explicit nil check even after &. usage
- ⚠ sig{} runtime checking adds overhead — T::Configuration.enable_checking_for_sigs_with_runtime_checks=true enables runtime type validation; in production agent services this adds measurable overhead per sig'd method call; disable runtime checking in production, enable only in development/test for agent performance
- ⚠ Tapioca requires periodic regeneration — RBI stubs go stale when gems update; agent CI should run bundle exec tapioca gems and commit updated RBIs; stale RBIs cause false type errors or missed real errors in agent code after gem upgrades; add tapioca regeneration to gem update workflow
- ⚠ Abstract and interface require T::Helpers — class AgentStrategy; extend T::Helpers; abstract! marks class abstract; interface! requires all methods to be abstract; forgetting include T::Helpers in agent base classes causes NoMethodError on abstract! at class definition time
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for Sorbet.
Scores are editorial opinions as of 2026-03-06.