Project

rixie

0.0
The project is in a healthy, maintained state
Rixie is a standalone Ruby gem for orchestrating AI agents. It provides a clean abstraction for LLM communication, tool execution, and multi-step reasoning strategies.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 0
 Project Readme

Gem Version CI Ruby License: MIT

Rixie

AI agent orchestration for Ruby.

Overview

Rixie is a standalone Ruby gem for orchestrating AI agents — no Rails required.

An Agent thinks and acts via an LLM and a set of tools, looping until it reaches a final answer. A Session manages the full conversation, accumulating history across multiple chats. A Strategy controls how a goal is accomplished: the default Simple strategy runs a single agent loop, while PlanExecute first builds a step-by-step plan and then executes each step in sequence.

Status: Rixie is in its 0.x series and pre-1.0 — the public API may still change between minor versions. It runs on Ruby 3.4+ and is exercised in CI on Ruby 3.4 and 4.0 with unit tests, integration tests, and a dependency vulnerability audit (bundler-audit).

Why Rixie?

Say you're building a research assistant. In a single conversation, a user might fire off a quick factual question, then ask for a deep multi-step investigation, then want to see exactly how the agent reasoned through one tricky step. Each of those wants a different execution strategy — a single loop, plan-then-execute, an explicit reasoning trace — yet they're all the same conversation, building on the same accumulated context.

Rixie is built for exactly that: a small, dependency-light orchestration layer that lets you switch reasoning strategy per call within a single, context-carrying session. Concretely:

  • A pure-Ruby core. The only runtime dependency is the standard-library logger; openai / nokogiri / cli-ui are loaded lazily, only for the features you use. No transitive tree to audit, no version conflicts dragged into your Gemfile, and no coupling to Rails.
  • Per-call strategy switching. Strategy is a chat argument, not a pre-wired graph (see Quick Start). It lives on the Task, not the Agent, so the agent stays the same while how it tackles a goal varies turn by turn — with the conversation's context shared automatically.
  • A small architecture you can read in one sitting. Five layers, linearly stacked (see Architecture). No hidden global event bus, no DSL, no metaprogramming — extending Rixie means implementing one plain object (a strategy, an adapter, or a Tool).

Installation

Add to your Gemfile:

gem "rixie"

Rixie keeps its runtime footprint small. The following gems are optional — add them only for the features you actually use. Each is loaded lazily and raises Rixie::ConfigurationError with an actionable message if missing.

gem "openai"     # required for the openai / ollama provider adapter (and any OpenAI-compatible endpoint)
gem "nokogiri"   # required for Rixie::Tool::Fetch and Rixie::Tool::WebSearch (DuckDuckGo HTML parsing)
gem "cli-ui"     # required to run the `rixie` CLI (bin/rixie)

# OpenTelemetry tracing (Subscribers::OpenTelemetry)
gem "opentelemetry-sdk"
gem "opentelemetry-exporter-otlp"

Quick Start

require "rixie"

Rixie.configure do |config|
  config.default_provider = "openai"
  config.default_model    = "gpt-4.1-mini"
end

session = Rixie::Session.new(instructions: "You are a helpful assistant.")
puts session.chat("What is the capital of France?")
# => "The capital of France is Paris."

Give the agent tools and it decides when to call them, loops until it has an answer, and carries the result into the rest of the conversation. Both tools below are pure Ruby — no extra gems required:

session = Rixie::Session.new(
  instructions: "You are a helpful assistant.",
  tools: [Rixie::Tool::Calculator, Rixie::Tool::CurrentTime]
)

# The agent calls the calculator tool, then answers from its result.
puts session.chat("What is 1234 * 5678?")
# => "1234 × 5678 = 7,006,652."

# The same session still has the previous turn in context.
puts session.chat("And what year is it right now?")
# => "It's 2026."

Pick a reasoning strategy per call by passing strategy:. The session carries context across them, so you can answer simply, plan a heavier step, or surface an explicit reasoning trace — all in one conversation:

# Default: a single agent loop.
session.chat("Outline a blog post about Ruby's Ractor.")

# Plan-then-execute: build a step-by-step plan, then run each step.
session.chat("Now write the full draft.",
             strategy: Rixie::Strategy::PlanExecute.new)

# ReAct: emit a Thought → Action → Observation trace you can inspect.
session.chat("Fact-check the draft's performance claims.",
             strategy: Rixie::Strategy::ReAct.new)

Send images to a vision-capable model by passing an array of content blocks instead of a string. Rixie defines a provider-agnostic content format; the adapter translates it to the provider's wire format, so the same input works across providers. Reading and base64-encoding the file is your responsibility:

require "base64"
image_data = Base64.strict_encode64(File.read("photo.png"))

session.chat([
  { type: "text",  text: "What's in this image?" },
  { type: "image", source: { type: "base64", media_type: "image/png", data: image_data } }
])

Passing a plain String (the common case) is unchanged. Only base64-encoded images are supported today — image URLs, PDFs, and audio/video are not.

Architecture

Session          # manages the full conversation; accumulates history across chats
└── Task         # accomplishes a single goal; owns a Strategy
    └── Run × N  # one LLM loop per step; calls Agent#think
        └── Agent         # thinks and acts: calls the LLM, executes tools, loops until done
Class Responsibility
Session Entry point. Resolves config, creates Agent and LLM::Client, exposes chat and live.
Task Runs a Strategy and accumulates Run results. Manages an EventListener.
Run Calls agent.think once. Accumulates tool-call steps.
Agent The think-act loop: calls the LLM, executes tools, emits events.
Strategy Controls how many Runs a Task executes. Simple = 1 Run; PlanExecute = plan + N Runs.

Features

  • Configuration — Configure providers, models, and persistence. Use OpenAI-compatible endpoints (GitHub Models, Ollama) or plug in a custom LLM adapter.
  • CLI — Interactive REPL with slash commands, tab completion, and extensibility via custom commands and tools.
  • Tools — Define your own tools and use the built-ins: web (Fetch, WebSearch, WikipediaSearch), filesystem (FileRead, FileList, FileSearch), utilities (CurrentTime, Calculator), and HumanInput for human-in-the-loop flows.
  • StrategiesSimple for single-loop tasks, PlanExecute for plan-then-execute multi-step tasks, ReAct for explicit Thought → Action → Observation reasoning traces.
  • Structured Output — Pass a JSON Schema to Session#chat(schema:) and get back a validated Ruby Hash instead of a String.
  • MCP — Connect to any MCP (Model Context Protocol) server over HTTP and import its tools automatically.
  • Multi-Agent Orchestration — Compose agents by wrapping a Session as a tool, with isolated context per sub-agent.
  • Subscribers — Observe agent behavior via the event bus — built-in logging, Langfuse and OpenTelemetry tracing, plus pluggable custom subscribers.
  • Streaming — Stream tokens, tool calls, and lifecycle events via Session#live.
  • Context Compression — Summarize accumulated history to control token usage in long sessions.
  • Store and Session Persistence — Persist and resume conversations with a default store or per-session store overrides.