Project

rlm-rb

0.0
A long-lived project that still receives updates
RLM.rb is a Ruby runtime spine for Recursive Language Models. It runs bounded, typed, auditable AI jobs over files, records, and application context. RLM.rb includes RubyLLM provider access, a dspy.rb signature adapter, the recursive prompt loop, file/context mounting, recursive sub-LM calls, typed final output, budget controls, trace events, and a best-effort trace_store hook.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 1.6
~> 1.0
~> 1.15
 Project Readme

RLM.rb

Gem Version CI

Recursive Language Models for Ruby.

RLM.rb is a plain Ruby runtime for typed, sandbox-oriented, auditable AI jobs over large application context. It integrates with RubyLLM for provider calls and dspy.rb for typed signatures.

Status: the released gem is v0.2.0. The current main branch contains the plain Ruby runtime spine, real RubyLLM and dspy adapters, subprocess isolation, context skills, eval export, local evals, optimizer integration, caching, and telemetry. Rails integration remains a v2 milestone.

Why

  1. Large context breaks simple prompting.
  2. Manual chunking and summarization are brittle.
  3. Hand-rolled agent loops have unclear state, unclear cost, and poor auditability.

RLM.rb replaces those with a bounded runtime where the model explores context programmatically, calls smaller typed LLM functions only when needed, and returns validated Ruby objects with a full execution trace.

Install

RLM.rb requires Ruby 3.3 or newer. Ruby 3.2 and older are not supported because dspy.rb is mandatory for the plain Ruby adapter milestone.

gem "rlm-rb"

Quick Start

require "dspy"
require "rlm"

class InvoiceExtraction < DSPy::Signature
  description "Extract normalized invoice fields from a vendor invoice."

  input do
    const :invoice_text, String
    const :vendor_id, Integer
  end

  output do
    const :vendor_name, String
    const :invoice_number, String
    const :total_cents, Integer
  end
end

RLM.configure do |config|
  config.root_lm = RLM::Lm::RubyLLM.new(model: "gpt-5-mini")
  config.sub_lm = RLM::Lm::RubyLLM.new(model: "gpt-5-mini")
  config.sandbox = RLM::Sandbox::Subprocess.new(timeout_seconds: 10)
end

result = RLM.predict(
  RLM::Signature::Dspy.new(InvoiceExtraction),
  input: {
    invoice_text: "Vendor: Acme\nInvoice: INV-001\nTotal: $100.00",
    vendor_id: 123
  },
  limits: RLM::Limits.new(max_iterations: 8, max_llm_calls: 25)
)

result.output
# => { vendor_name: "Acme", invoice_number: "INV-001", total_cents: 10000 }

For a deterministic no-provider test path, use RLM::Lm::Mock and RLM::Sandbox::UnsafeInProcess. The unsafe sandbox executes generated code in the host process and is only for dev/test.

Architecture Layers

  • Interface: typed task contracts through RLM::Signature and RLM::Signature::Dspy.
  • Inference: provider and model calls through RLM::Lm::*, including RLM::Lm::RubyLLM.
  • Rendering: response protocols through tags, JSON, XML, provider-native JSON, and host-owned BAML adapters.
  • Call graph: recursive runtime execution through RLM::Runtime, sandbox helpers, tools, and sub-signatures.
  • Evals: trace/result export, local evals, and dspy optimizer entrypoints.

Current Surface

Component Status
RLM.configure / RLM.config Ready
RLM::Limits Ready
RLM::File and RLM::Context Ready with subprocess-safe manifests and mounted file paths
RLM::Trace, RLM::Result, RLM::TraceReplay Ready
RLM::Sandbox::Subprocess / RLM::Sandbox::Docker / RLM::Sandbox::Remote / RLM::Sandbox::Wasm Ready for local, container, remote, and host-owned WASM isolation
RLM::Sandbox::UnsafeInProcess Dev/test only
RLM::Tool, RLM::ToolRegistry, tool schemas, tool authorization Ready for read-only tools
RLM::Skill plus CSV, directory, PDF, HTML, and browser skills Ready for dependency-free context inspection
RLM::Predict, RLM::Runtime, RLM::Runtime::Bridge Ready
RLM::PromptBuilder, RLM::CodeExtractor, RLM::ResponseProtocol Ready
RLM::EvalExample, RLM::EvalExporter, RLM::Eval.run Ready
RLM::Optimizer::Dspy Ready for caller-supplied dspy teleprompters and named presets
RLM::TraceStore / RLM::TraceStore::Memory / RLM::TraceStore::ActiveRecord Ready for plain Ruby and Rails storage
RLM::Review / RLM::Review::MemoryQueue Ready for plain Ruby review routing
RLM::Dashboard.summary Ready for host-app dashboard metrics
Runtime caching Ready for subcalls, file reads, tools, and skills
Optional telemetry spans, ActiveSupport notifications, and dspy spans Ready through RLM::Telemetry
RLM::Lm::RubyLLM and RLM::Signature::Dspy Ready
Optional Rails Railtie Ready through require "rlm/rails" when Rails is loaded
Rails install generator Ready for initializer, trace model, and trace migration setup
ActiveStorage adapter Ready through RLM::Rails::ActiveStorage
ActiveJob / Sidekiq / GoodJob examples Ready through generated RlmPredictJob

Guides

  • Plain Ruby usage: configuration, live example, mock runtime, dspy signatures, and response protocols.
  • Runtime features: trace stores, tools, skills, evals, dspy optimization, caching, and telemetry.
  • Production notes: intended Rails setup, error handling, production safety, and development commands.
  • Product requirements: long-form product direction and milestone notes.

Live Example

The gem ships one opt-in live example:

bundle exec ruby examples/plain_ruby_invoice_extraction.rb

By default it exits before provider credential checks. To run the live path:

RLM_RUN_LIVE_EXAMPLE=1 OPENAI_API_KEY="$OPENAI_API_KEY" \
  bundle exec ruby examples/plain_ruby_invoice_extraction.rb

Set RLM_EXAMPLE_MODEL and RLM_EXAMPLE_SUB_MODEL to override the default models.

API Reference

RLM.rb integrates with these upstream libraries:

License

MIT, see LICENSE.txt.