Model or dataset
BoxcarsAI/boxcars avatar
BoxcarsAI/boxcars

Boxcars: A Ruby Tool-Orchestration Framework for LLM Applications

Building applications with composability using Boxcars with LLM's.

461 stars42 forksRubyMIT

At a glance

What is it?
Boxcars packages tools as Ruby objects and runs them through a Train or a StationAgent, with read-only SQL and ActiveRecord defaults. It fits Rails teams that want provider-agnostic LLM orchestration without leaving Ruby, and it assumes you are willing to declare optional provider gems yourself.
Who is it for?
Adopt Boxcars if you have a Rails or plain Ruby codebase and want tool orchestration that reads like the rest of your application code, particularly if you need SQL or ActiveRecord tools with read-only defaults and a mixed local plus MCP tool set.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Boxcars targets: LLM glue code spread across a Rails app

Most Ruby teams that add an LLM feature end up with provider-specific wrappers. One service object calls OpenAI directly, a background job formats a prompt by hand, a controller parses a JSON blob, and none of it shares a tool definition. Boxcars is aimed at that situation. The README describes it as a Ruby framework for building LLM-powered systems with less cognitive load, especially for Ruby and Rails teams, and states the goal plainly: one gem that can search, calculate, query data, call external APIs, run retrieval, and coordinate all of that in one runtime.

The intended audience is narrower than the description suggests. The framework's vocabulary (Boxcar, Train, Engine, StationAgent) is Ruby-native, and the optional dependency list includes activerecord, sequel, and pgvector, so the design assumes you already have a Rails or Ruby data layer you want the model to reach. If your stack is Python, nothing here transfers. If your stack is Ruby but your LLM usage is a single prompt-and-parse call, the orchestration layer is overhead you do not need yet.

Boxcar, Train, Engine, StationAgent: the four objects that carry the design

The README defines five concepts, all inside a module named Boxcars. A Boxcar is a single-purpose tool: search, math, SQL, ActiveRecord query, or API call. It may use an Engine for LLM work. A Train takes a list of Boxcars plus an Engine and decomposes a problem so individual Boxcars can solve it. A Prompt is what an Engine consumes to generate text, with built-in prompts you can customize. An Engine generates text from a Prompt and is the provider boundary. A StationAgent is a higher-level abstraction over Train with lifecycle callbacks, agent-as-tool nesting, handoffs, and event streaming, documented in docs/agents_guide.md. VectorStore is the sixth piece, a place to store and query vectors.

The mechanism is composition rather than a monolithic agent class. You package domain logic as Boxcar objects and reuse them across assistants, jobs, and services. Two orchestration modes exist and they are not equivalent. Boxcars::ZeroShot is described as the legacy text ReAct path, while Boxcars::ToolTrain uses native provider tool calling. That distinction matters when you pick a model: ReAct works through text parsing, so it can run against engines that lack a tool-calling API, while native tool calling depends on the provider supporting it. The README does not state which engines support which mode, so that is something to confirm per provider before committing.

Getting a first Train running: gems, commands, and the optional-dependency rule

Boxcars requires Ruby 3.3 or newer. Installation is the standard two-step: add gem 'boxcars' to your Gemfile and run bundle install, or run gem install boxcars directly. The base install is deliberately thin. Provider and tooling dependencies are optional, and the README lists them explicitly: openai (>= 0.30) for OpenAI and OpenAI-compatible engines, ruby-anthropic for Boxcars::Anthropic, google_search_results for Boxcars::GoogleSearch, faraday for Boxcars::Perplexityai and Boxcars::Cohere, activerecord for Boxcars::ActiveRecord and Boxcars::SQLActiveRecord outside Rails, sequel for Boxcars::SQLSequel, pg and pgvector for the Pgvector vector-store backend, nokogiri for XML trains and URLText HTML extraction, and hnswlib for HNSW vector store paths.

The failure mode here is explicit and helpful: if a feature is used without its optional gem installed, Boxcars raises a setup error naming the gem to add. That is a better experience than a NoMethodError deep in a call stack.

The README gives three runnable examples. A single Boxcar: Boxcars::Calculator.new, then calc.run("What is pi to the fourth power divided by 22.1?"). A Train: build an array of Boxcars::Calculator.new and Boxcars::GoogleSearch.new, pass it to Boxcars.train.new(boxcars: boxcars), then call run on a question that mixes both tools. An agent: Boxcars::StationAgent.new with instructions, tools, and model: "sonnet", then agent.run on a math question. Note the model string in that example is a short alias, not a provider model ID, so the mapping from alias to provider is something the docs handle rather than the README.

Read-only by default: the security posture and how to change it

The most consequential design decision in the README concerns data access. Both ActiveRecord and the SQL boxcars default to read-only mode and reject write operations with a Boxcars::SecurityError. To allow writes you either disable read-only mode or provide an approval callback, with details and examples in the Boxcars Guide under read-only defaults and security.

This is the right default for the stated use cases (internal copilots, retrieval-first assistants, operations bots), because a model-generated UPDATE is a different risk class from a model-generated SELECT. The trade-off is real: an operations bot whose whole purpose is completing multi-step actions will hit the write path quickly, and disabling read-only mode wholesale removes the guard for every query in that Train, not just the intended one. The approval callback is the more interesting option because it keeps a human or a policy check in the loop, but the README does not describe its signature or how it is invoked, so read the guide before designing around it. If your workflow needs unattended writes, Boxcars is asking you to make that decision explicitly, and you should treat the guide as required reading rather than optional.

MCP integration and the mixed-tool runtime

Boxcars connects MCP servers over stdio and merges MCP tools with local Boxcars in one tool-calling runtime. The README lists this as an MCP-ready integration and as one of the things you can build quickly: local plus remote agent workflows that blend your own Ruby tools with MCP-discovered tools.

The practical consequence is that tool count becomes a design constraint. Every MCP server you attach contributes its tools to the same selection pool as your hand-written Boxcars, and the model chooses among all of them. The README does not describe how tool names are namespaced when a local Boxcar and a remote MCP tool collide, nor how many tools a Train can carry before selection quality degrades. Those are the questions to answer with a small test harness before wiring five servers into a production assistant. The upside is genuine: a tool you write in Ruby and a tool someone else published over MCP are addressed through the same calling convention, so you are not maintaining two integration paths.

Where Boxcars is the wrong tool

Several constraints are visible in the material. Ruby 3.3 or newer is a hard floor, and the upgrade notes state that runtime ActiveSupport/ActiveRecord targets are now ~> 8.1, which will exclude applications pinned to older Rails versions until they move. The optional-gem model means a lean base install but more Gemfile bookkeeping, and every provider you add is a separate dependency to track.

The upgrade notes also indicate a framework in motion. Boxcars::Openai now defaults to gpt-5-mini and uses the official OpenAI client path. Boxcars::Cohere now defaults to command-a-03-2025 because legacy command-r model IDs were retired by Cohere. rest-client is no longer a runtime dependency and Swagger workflows now use Faraday guidance. intelligence and gpt4all moved to optional, so Boxcars::IntelligenceBase and Boxcars::Gpt4allEng require you to add those gems yourself. The README points to UPGRADING.md for migration guidance toward v1.0, including tool-calling changes and alias deprecations, and no releases were retrieved. Taken together: this is a project whose interfaces are still settling, and a team that needs a frozen dependency with a long support tail should weigh that. A single-purpose script that calls one provider once is also a poor fit; the Train and Engine layers only pay off when you have multiple tools to coordinate or multiple providers to swap.

The alternative: LangChain and what actually differs

Boxcars states it is inspired by LangChain but brings a Ruby-first design that favors practical composition over framework lock-in. The difference is not just language porting. LangChain's center of gravity is Python and JavaScript, with a broad ecosystem of integrations and chain abstractions; adopting it in a Rails application means running a second runtime alongside Ruby, or accepting an ecosystem that does not share your application's objects.

Boxcars keeps the tool definitions inside your Ruby process. A Boxcar is an object you can instantiate in a controller, a job, or a service object, and the Train that coordinates them runs in the same runtime as your ActiveRecord models. That is the concrete difference: no cross-language boundary, and direct access to the data layer the README lists as first-class (SQL, ActiveRecord, vector search). The cost is ecosystem size. LangChain's integration surface is larger and its release cadence is more established, while Boxcars is approaching v1.0 with an UPGRADING.md as the migration document. If your team is Ruby-only and your tools are your own domain logic, Boxcars removes a language boundary. If you need a long list of pre-built third-party integrations, LangChain has more of them, and that is a reason to choose it despite the extra runtime.

Maintenance cost, licensing, and what to check before you commit

Boxcars is MIT licensed, per the badge and the LICENSE.txt path in the repository. MIT is permissive, so the usual implication is that you can use, modify, and redistribute it with the license and copyright notice retained, but that is a general description of the license rather than advice about your situation; read LICENSE.txt and your own legal guidance.

Ongoing cost comes from three places. First, optional gems: every provider and backend you enable is a dependency you upgrade on your own schedule, and the intelligence and gpt4all paths now require explicit Gemfile entries. Second, provider model defaults, which the project changes as vendors retire model IDs, as the Cohere command-r to command-a-03-2025 note shows; if you rely on defaults rather than pinning model names, an upgrade can change which model your application calls. Third, the migration path itself: UPGRADING.md exists for v1.0, covering tool-calling, alias deprecations, and the OpenAI client switch, so budget for a reading pass before any major version bump. There were no retrieved releases, so there is no published version history in this material to gauge cadence against; check the repository's tags and UPGRADING.md directly before you plan an upgrade window.

Editorial conclusion

Adopt Boxcars if you have a Rails or plain Ruby codebase and want tool orchestration that reads like the rest of your application code, particularly if you need SQL or ActiveRecord tools with read-only defaults and a mixed local plus MCP tool set. Do not adopt it if you are not on Ruby 3.3 or newer, or if you need a project with published release history, because the README shows no retrieved releases and points to an UPGRADING.md for a v1.0 that is still described as being approached. Before writing code, verify three things in your own environment: that Ruby 3.3+ is available, that you have added the optional gems for every Boxcar and Engine you plan to use, and that your write paths either disable read-only mode deliberately or supply an approval callback, since the default is to raise Boxcars::SecurityError.

Official sources

  1. BoxcarsAI/boxcars on GitHub
  2. Issues
  3. License: MIT
  4. README
Community notes

Community notes