Core Features
The agent pipeline (Brute.agent, .use, .run, .start),
the middleware catalog, Brute’s message
format, the MessageTransport
pattern with shipped transports for four LLM
libraries, and the tool system.
Brute treats an agent turn the way Rack treats an HTTP request: an env hash flowing through a middleware stack toward a terminal app. The middleware handles the agentic machinery — the tool loop, session persistence, the system prompt, iteration guards. The terminal app is a proc you write with whatever LLM library you prefer: ruby_llm, llm.rb, the official openai or anthropic gems, or raw HTTP. Brute depends on none of them.
require "brute"require "ruby_llm"
agent = Brute.agent .use(Brute::Middleware::SessionLog, path: "tmp/session.jsonl") .use(Brute::Middleware::SystemPrompt) .use(Brute::Middleware::Loop::ToolResult) .use(Brute::Middleware::MaxIterations) .use(Brute::Middleware::DefaultToolPipeline, tools: Brute::Tools::ALL) .run do |env| # The LLM call — yours, with your library. A MessageTransport # translates between Brute's message format and the library's. response = provider.complete( Brute::MessageTransport::RubyLLM.dump_all(env[:messages]), tools: rubyllm_tools(env[:tools]), model: model, ) Brute::MessageTransport::RubyLLM.wrap_each(response) { |m| env[:messages] << m } end
agent.start("What files are in the current directory?")The proc makes ONE completion per pass; the ToolPipeline middleware executes whatever tools the model called, and Loop::ToolResult sends the results back down the stack until the model answers with text. Brute is the turn manager — the LLM library is just a client.
Head to Getting Started for a complete runnable walkthrough.
Core Features
The agent pipeline (Brute.agent, .use, .run, .start),
the middleware catalog, Brute’s message
format, the MessageTransport
pattern with shipped transports for four LLM
libraries, and the tool system.
Advanced
Sub-agents (agents as tools), session persistence, skills, events, and serving agents over HTTP.
Examples
Runnable agents, including the same agent on all four supported LLM libraries.
brute.gemspec names no LLM library. The terminal run proc owns provider, model, and credentials.Array of Brute::Message — an immutable Data value with role, content, tool_calls, tool_call_id. Anything that duck-types those methods rides along.