Build AI in Rails.
Agents are controllers.
Open-source, provider-agnostic AI agents for Rails. Actions, callbacks and views you already know. MIT, free forever.
Weekly release notes, event announcements and updates. Docs · GitHub
$ bundle add activeagent
·
$ rails generate active_agent:install
- *MIT
- #Rails 7.2 to 8.1
- @Ruby 3.2+
- {}10 providers
class SupportAgent < ApplicationAgent
generate_with :anthropic, model: "claude-sonnet-4-5"
# current_user is whoever made the call
before_action :authorize_tickets!
delegate_to RefundAgent, budget: { max_calls: 1 }
def reply
prompt(
message: params[:message],
tools: TicketTools.tool_definitions,
mcps: [ { url: "https://mcp.stripe.com" } ]
)
end
def find_tickets(**filters)
TicketTools.call("find_tickets",
actor: current_user, **filters)
end
end
# system prompt: app/views/agents/support/instructions.md
SupportAgent.as(current_user)
.with(message: "Where is my order 4821?")
.reply.generate_now
Running agents in production? Monitor them at activeagents.ai
Three gems. One wire format.
The framework reports what every agent did. The dashboard stores and shows it. The platform is that dashboard, hosted. The same YAML block moves a trace from one to the next.
Agents, actions and prompt templates. Ten providers, tools, MCP servers, delegation, structured output and streaming. Evaluations and telemetry ship in the gem.
local_storage: true
A mountable Rails engine. Traces with span waterfalls, metrics, interactions, evaluations, the agent builder, the Run Agent workbench, and your agents served as an MCP server. On your database.
endpoint: api.activeagents.ai
The same engine, multi-tenant. Workspaces and seats, retention and quotas by plan, published evaluation reports, managed sandboxes. Every workspace starts with a free trial.
Also in the family:
solid_agent persists contexts, memory, runs and cost as models you own.
activeagents-telemetry reports RubyLLM apps on the same wire format.
Agents are controllers.
Actions, callbacks, params and views, for AI. Tools are Ruby methods, MCP servers are a declaration, and another agent is just another tool. Everything below is in the MIT gem.
@Agents are controllers
Actions, before_action, params. Run now, or later on Active Job.
class TranslationAgent < ApplicationAgent
generate_with :openai, model: "gpt-4o-mini"
before_action :load_glossary
def translate
prompt # renders translate.md.erb
end
end
TranslationAgent.with(text: "Hello", locale: "ja")
.translate.generate_now
TranslationAgent.with(text: "Hello", locale: "ja")
.translate.generate_later # Active Job
docs/agents ->
*Action Prompt
Prompts are views. ERB, partials and layouts, plus an instructions file per agent.
app/views/agents/translation/
instructions.md # the system prompt
translate.md.erb # the user turn
translate.json # a response schema, if any
<%# translate.md.erb %>
Translate into <%= params[:locale] %>, keeping the tone:
<%= params[:text] %>
docs/actions ->
>>Any provider
OpenAI, Anthropic, Gemini, Bedrock, Azure, Ollama, OpenRouter, Requesty, DeepSeek, RubyLLM. One line to switch.
generate_with :anthropic, model: "claude-sonnet-4-5"
generate_with :openai, model: "gpt-4o-mini"
generate_with :gemini, model: "gemini-2.5-flash"
generate_with :ollama, model: "qwen3:8b"
generate_with :deepseek, model: "deepseek-flash"
generate_with :ruby_llm, model: "mistral-large-latest"
# or per environment, in config/active_agent.yml
docs/providers ->
[]Tools from your schema
Bounded, allowlisted read tools generated from a model, scoped to whoever is asking.
class TicketTools < ActiveAgent::SchemaTools
model Ticket
filterable :status, :assignee_id, :opened_on
returns :id, :subject, :status, :opened_on
scope_by_policy # TicketPolicy::Scope, per caller
end
TicketTools.tool_names
# => ["find_tickets", "count_tickets", "get_ticket"]
docs/tools ->
{}MCP servers
Remote url: or local command: servers. Native where the provider supports it, bridged everywhere else.
def research
prompt(
params[:question],
mcps: [
{ name: "github",
url: "https://api.githubcopilot.com/mcp/",
authorization: ENV["GITHUB_TOKEN"] },
{ name: "files",
command: "mcp-server-filesystem",
args: [ Rails.root.to_s ] }
]
)
end
docs/mcps ->
->Delegation
Another agent as a tool, under a declared schema and a cost and latency budget.
class ClassifierAgent < ApplicationAgent
delegation :classify, description: "Classify a ticket" do
string :body, required: true
returns { string :category, enum: %w[billing bug account] }
end
def classify(body:) = prompt(message: body)
end
class TriageAgent < ApplicationAgent
delegate_to ClassifierAgent, budget: { max_calls: 1 }
end
docs/delegation ->
=Evaluations as tests
Replay scenarios across models, score them, and get one fault and one fix per failure.
scenarios = ActiveAgent::Evals::ScenarioParser.scenarios(<<~TEXT)
# Orders
Where is my order 4821? | tools: find_tickets
Cancel my subscription | not_contains: I cannot
TEXT
report = ActiveAgent::Evals::Runner.new(
scenarios: scenarios,
models: ActiveAgent::Evals::ModelSpec.parse_all(
%w[claude-sonnet-4-5 ollama/qwen3:8b], default_provider: "anthropic"),
replay: ->(scenario, spec) { SupportAgent.evaluate(scenario.prompt, model: spec.model, provider: spec.provider) }
).call
report.to_html # or to_markdown, to_json, or publish it to the dashboard
docs/evaluations ->
- #Structured output: JSON schemas as views
- ~Streaming with open, chunk and close callbacks
- :Retries with backoff, from each provider SDK
- +Callbacks before, after and around every generation
- @
current_useron every call, tool and sub-agent - vReleases: a digest of what the model is given, on every trace
- *Embeddings for search and RAG
- ?A mock provider for tests, no keys needed
- TToken usage and cost on every response
See your agents while you build
The dashboard is its own MIT gem: a Rails engine that mounts in your app. Add it, turn on local
telemetry, and every generation appears at /activeagents as a
trace with a span waterfall, token counts and the agent release that produced it. It is the same
engine the hosted platform runs, against your own database.
$ bundle add actionagent
$ rails generate action_agent:install && rails db:migrate
# config/active_agent.yml
telemetry:
enabled: true
local_storage: true # open /activeagents
| Scenario | claude-sonnet-4-5 judge's pick | ollama/qwen3:8b |
|---|---|---|
| Passed | ||
| Cost per run | ~$0.0243 · judge ~$0.0015 | ~$0.0000 |
| Where is my order 4821? find_tickets | [+] 0.96 find_tickets | [+] 0.81 find_tickets |
| Refund my last invoice refund | [!] 0.42 missing_tool | [!] 0.31 missing_tool |
| Cancel my subscription | [+] 0.91 | [!] 0.55 ungrounded_answer |
- 01GitHub connected · acme/support-app[+]
- 02Checkout sandbox booted · mainready
- 03Claude Code session · sonnetrunning
- 04Suite re-run against the sandboxqueued
- 05Diff: +41 -6 · instructions.mdreview
- @Agents. Scorecards, versions, releases and the pooled eval pass rate per agent.
- []Tools and MCP Services. The roster each agent is offered, with the server that serves each tool.
- [>]Session Replay. Watch an agent-driven session step by step with its trace log beside it.
- >Ask ActiveAgents. Ask which scenarios failed and why, with links to the evidence. Development and test only.
For a team or a fleet of apps,
mount it in one shared app and point the others' telemetry at <mount>/api/traces, with your own authentication in front.
Self-hosted guide
Free, and free forever.
Four MIT gems with no usage limits. Take the framework alone, or add the dashboard, persistence and tracing for apps that call models another way.
@activeagent
The framework. Agents, actions and prompt templates; ten providers; tools, schema tools, MCP servers and delegation; structured output and streaming; evaluations and telemetry built in.
->actionagent
The dashboard, as a mountable Rails engine. Traces, metrics, interactions and evaluations; the agent builder, versions and the Run Agent workbench; your agents served as an MCP server. Prebuilt assets, no JavaScript build in your app.
#solid_agent
Persistence as models you own. Conversation context, agent-curated long-term memory, durable runs
with progress events, tool result caching, model pricing, and portable agent manifests
(.agent.md, dotprompt, CrewAI).
~activeagents-telemetry
Tracing for Ruby apps that call models without the framework. The RubyLLM adapter reports every chat turn as a trace on the same wire format, to a mounted dashboard or the platform. Bodies are sent only when you say so.
+Need it hosted?
The platform at activeagents.ai runs the same dashboard for a team: workspaces and seats, retention and quotas by plan, published evaluation reports from CI, managed sandboxes and support. Every workspace starts with a free trial, and your app only needs the framework gem.
Questions people ask first
Is it really free?
+
Yes. The framework, every provider, the dashboard engine, persistence and the telemetry adapters are MIT licensed with no usage limits. The hosted platform at activeagents.ai is the commercial product: it runs the same dashboard for a team and charges for ingestion, retention, quotas, managed sandboxes and support.
How do I install it?
+
Add activeagent and run rails generate active_agent:install. That writes config/active_agent.yml and an ApplicationAgent. For the dashboard, add actionagent, run rails generate action_agent:install and rails db:migrate, then turn on telemetry.local_storage.
Which providers are supported?
+
OpenAI (Chat Completions and the Responses API), Anthropic, Google Gemini, AWS Bedrock, Azure OpenAI, Ollama, OpenRouter, Requesty, DeepSeek, and RubyLLM, which brings its own registry of models. A mock provider runs the whole pipeline in tests with no keys. Switch providers with one line.
Does MCP work with every provider?
+
Yes. Every provider accepts mcps:. Anthropic and the OpenAI Responses API run remote servers natively; for the others, and for every local command: server, the framework connects, lists the tools and exposes them as functions. Tool lists are cached, so a warm cache only connects when the model calls a tool.
How do I see what my agents are doing?
+
Mount the actionagent engine and every generation appears at /activeagents as a trace with a span waterfall, token counts (input, output, cached, thinking), provider, model and release. Interactions show the conversation behind each trace, Metrics shows the golden signals, and Evaluations replays scenario suites across models. For production monitoring without hosting it, point telemetry at activeagents.ai.
Does my data leave my infrastructure?
+
Not unless you send it somewhere. The framework and the mounted dashboard run entirely in your app against your own database. Hosted telemetry is opt-in through config/active_agent.yml, and even then prompts and completions are sent only when capture_bodies is on.
Does it work with an existing Rails app?
+
That is the point. Agents live in app/agents beside your controllers, prompt templates live in app/views, generations run inline or on Active Job, and current_user flows from your authentication into every callback, tool and sub-agent so Pundit or CanCanCan authorize an agent the way they authorize a controller. Rails 7.2 through 8.1 and Ruby 3.2 and up.
Ship your first agent this afternoon.
MIT licensed. Built for Rails. No keys required to start: the mock provider runs the full pipeline while you wire things up.