RCrewAI

Ruby AI Production Ready

Build powerful AI agent crews in Ruby that work together to accomplish complex tasks.

RCrewAI is a Ruby implementation of the CrewAI framework, allowing you to create autonomous AI agents that collaborate to solve problems and complete tasks with human oversight and enterprise-grade features.

πŸš€ Features

  • πŸ€– Intelligent Agents: AI agents with reasoning loops, memory, and tool usage capabilities
  • πŸ”— Multi-LLM Support: OpenAI, Anthropic (Claude), Google (Gemini), Azure OpenAI, and Ollama
  • πŸ› οΈ Rich Tool Ecosystem: Web search, file operations, SQL, email, code execution, PDF processing, and custom tools
  • 🧠 Cognitive Memory: Semantic recall (embeddings + cosine) with optional SQLite persistence and short-term/long-term/entity/tool memory types
  • 🀝 Human-in-the-Loop: Interactive approval workflows, human guidance, and collaborative decision making
  • ⚑ Advanced Task System: Dependencies, retries, async/concurrent execution, and context sharing
  • πŸ—οΈ Hierarchical Teams: Manager agents that coordinate and delegate tasks to specialist agents
  • πŸ”’ Production Ready: Security controls, error handling, logging, monitoring, and sandboxing
  • 🎯 Flexible Orchestration: Sequential, hierarchical, and concurrent execution modes
  • 🌊 Flows: Event-driven workflows with start/listen/router, branching, and persistent state
  • πŸ“š Knowledge (RAG): Ground agents in your own documents with built-in retrieval
  • πŸ’Ž Ruby-First Design: Built specifically for Ruby developers with idiomatic patterns

πŸ“¦ Installation

Add this line to your application's Gemfile:

gem 'rcrewai'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install rcrewai

πŸƒβ€β™‚οΈ Quick Start

require 'rcrewai'

# Configure your LLM provider
RCrewAI.configure do |config|
  config.llm_provider = :openai  # or :anthropic, :google, :azure, :ollama
  config.temperature = 0.1
end

# Create intelligent agents with specialized tools
researcher = RCrewAI::Agent.new(
  name: "researcher",
  role: "Senior Research Analyst",
  goal: "Uncover cutting-edge developments in AI",
  backstory: "Expert at finding and analyzing the latest tech trends",
  tools: [RCrewAI::Tools::WebSearch.new],
  verbose: true
)

writer = RCrewAI::Agent.new(
  name: "writer", 
  role: "Tech Content Strategist",
  goal: "Create compelling technical content",
  backstory: "Skilled at transforming research into engaging articles",
  tools: [RCrewAI::Tools::FileWriter.new]
)

# Create crew with sequential process
crew = RCrewAI::Crew.new("ai_research_crew")
crew.add_agent(researcher)
crew.add_agent(writer)

# Define tasks with dependencies
research_task = RCrewAI::Task.new(
  name: "research_ai_trends",
  description: "Research the latest developments in AI for 2024",
  agent: researcher,
  expected_output: "Comprehensive report on AI trends with key insights"
)

writing_task = RCrewAI::Task.new(
  name: "write_article",
  description: "Write an engaging 1000-word article about AI trends",
  agent: writer,
  context: [research_task],  # Uses research results as context
  expected_output: "Publication-ready article saved as ai_trends.md"
)

crew.add_task(research_task)
crew.add_task(writing_task)

# Execute - agents will reason, search, and produce real results!
results = crew.execute
puts "βœ… Crew completed #{results[:completed_tasks]}/#{results[:total_tasks]} tasks"

🎯 Key Capabilities

🧠 Advanced Agent Intelligence

  • Multi-step Reasoning: Complex problem decomposition and solving
  • Tool Selection: Intelligent tool usage based on task requirements
  • Context Awareness: Memory-driven decision making from past executions
  • Learning Capability: Short-term and long-term memory systems

πŸ› οΈ Comprehensive Tool Ecosystem

  • Web Search: DuckDuckGo integration for research
  • File Operations: Read/write files with security controls
  • SQL Database: Secure database querying with connection management
  • Email Integration: SMTP email sending with attachment support
  • Code Execution: Sandboxed code execution environment
  • PDF Processing: Text extraction and document processing
  • Custom Tools: Extensible framework for building specialized tools

🀝 Human-in-the-Loop Integration

  • Interactive Approval: Human confirmation for sensitive operations
  • Real-time Guidance: Human input during agent reasoning processes
  • Task Confirmation: Human approval before executing critical tasks
  • Result Validation: Human review and revision of agent outputs
  • Error Recovery: Human intervention when agents encounter failures

πŸ—οΈ Enterprise-Grade Orchestration

  • Hierarchical Teams: Manager agents coordinate and delegate to specialists
  • Async Execution: Parallel task processing with intelligent dependency management
  • Delegation Systems: Automatic task assignment based on agent capabilities
  • Process Types: Sequential, hierarchical, and consensual execution modes

πŸ”§ LLM Provider Support

# OpenAI (GPT-4, GPT-3.5, etc.)
RCrewAI.configure do |config|
  config.llm_provider = :openai
  config.openai_api_key = ENV['OPENAI_API_KEY']
  config.model = 'gpt-4'
end

# Anthropic Claude
RCrewAI.configure do |config|
  config.llm_provider = :anthropic
  config.anthropic_api_key = ENV['ANTHROPIC_API_KEY'] 
  config.model = 'claude-3-sonnet-20240229'
end

# Google Gemini
RCrewAI.configure do |config|
  config.llm_provider = :google
  config.google_api_key = ENV['GOOGLE_API_KEY']
  config.model = 'gemini-pro'
end

# Azure OpenAI
RCrewAI.configure do |config|
  config.llm_provider = :azure
  config.azure_api_key = ENV['AZURE_OPENAI_API_KEY']
  config.azure_endpoint = ENV['AZURE_OPENAI_ENDPOINT']
  config.model = 'gpt-4'
end

# Local Ollama
RCrewAI.configure do |config|
  config.llm_provider = :ollama
  config.ollama_url = 'http://localhost:11434'
  config.model = 'llama2'
end

Per-agent LLM

The RCrewAI.configure block sets the crew-wide default. Any agent can override it with the llm: option, so a single crew can mix providers and models β€” for example a cheap model for workers and a stronger one for the manager:

# Provider only (uses that provider's configured model + key)
researcher = RCrewAI::Agent.new(name: 'researcher', role: '...', goal: '...',
                                llm: :anthropic)

# Provider + model (and optionally api_key / temperature)
manager = RCrewAI::Agent.new(name: 'manager', role: '...', goal: '...',
                             llm: { provider: :anthropic, model: 'claude-3-opus-20240229' })

worker = RCrewAI::Agent.new(name: 'worker', role: '...', goal: '...',
                            llm: { provider: :openai, model: 'gpt-4o-mini' })

# Or pass a pre-built client instance
worker = RCrewAI::Agent.new(name: 'worker', role: '...', goal: '...',
                            llm: my_client)

Omit llm: to use the global RCrewAI.configure settings. Overrides never mutate the global configuration.

πŸ“€ Structured Output, Guardrails & File Output

Tasks can validate, transform, and persist their output:

task = RCrewAI::Task.new(
  name: 'extract',
  description: 'Extract the article title and word count as JSON',
  agent: analyst,

  # Structured output β€” validated & coerced against a JSON schema.
  # Non-conforming output re-runs the agent with the error fed back.
  output_schema: {
    type: 'object',
    properties: { title: { type: 'string' }, words: { type: 'integer' } },
    required: ['title']
  },

  # Guardrail β€” ->(output) { [ok, value_or_error] }. On rejection the agent
  # re-runs (up to guardrail_max_retries) with the reason appended.
  guardrail: ->(out) { [out.length < 5000, 'must be under 5000 chars'] },
  guardrail_max_retries: 3,

  # Persist the result. Parent dirs are created unless create_directory: false.
  output_file: 'out/report.md',
  markdown: true
)

task.execute
task.structured_output  # => { "title" => "...", "words" => 1234 }
task.raw_result         # => the unprocessed string the agent produced

πŸ—ΊοΈ Planning

Enable planning: on a crew to run a planner pass before execution. The planner drafts a short plan for each task and folds it into the task description, giving the executing agent a head start:

crew = RCrewAI::Crew.new('research_crew', planning: true)
# Optionally use a dedicated (e.g. stronger) planner model:
crew = RCrewAI::Crew.new('research_crew', planning: true,
                         planning_llm: { provider: :anthropic, model: 'claude-3-opus-20240229' })

Planning is best-effort: if the planner errors or returns unparseable output, the crew runs with the original tasks unchanged.

πŸ‹οΈ Training & Testing

Iterate on a crew by training it with feedback or scoring repeated runs:

# Train: run N times, collect feedback after each run, persist to JSON.
crew.train(n_iterations: 3, filename: 'training.json')

# Provide feedback programmatically instead of prompting a human:
crew.train(n_iterations: 3, filename: 'training.json',
           feedback: ->(iteration, result) { "run #{iteration}: #{result[:success_rate]}%" })

# Test: run N times and score each run (defaults to success_rate).
crew.test(n_iterations: 5)
# => { iterations: 5, scores: [...], average_score: 92.0 }

πŸͺ Kickoff Hooks & Batch Runs

Run setup/teardown around a crew, and batch it over many inputs:

crew.before_kickoff { |inputs| inputs.merge(started_at: Time.now) } # may transform inputs
crew.after_kickoff  { |result| notify(result); result }            # may transform result

crew.execute(inputs: { topic: 'ruby' })
crew.last_inputs   # => the (possibly transformed) inputs the run used

# Batch: run the crew once per input set, results returned in order.
results = crew.kickoff_for_each(inputs: [
  { topic: 'ruby' },
  { topic: 'python' }
])

⏱️ Rate Limiting

Cap an agent's LLM calls to stay under provider limits. Calls beyond the cap block until the rolling 60-second window frees up:

agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...', max_rpm: 20)

The limiter (RCrewAI::RateLimiter) is thread-safe, so it holds under async execution. max_rpm: nil (the default) or 0 means unlimited.

🧠 Reasoning

Have an agent think through a plan before answering. The reasoning trace is surfaced on the result and does not pollute task.result:

agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...',
                           reasoning: true, max_reasoning_attempts: 3)

result = agent.execute_task(task)
result[:reasoning]   # => the plan the agent drafted before answering
result[:content]     # => the final answer

Off by default. If the reasoning pass keeps returning empty output past max_reasoning_attempts, the agent proceeds without a plan.

πŸͺŸ Context Window Management

Keep long tool-use loops or large injected context from overflowing the model's context window. When enabled, the oldest non-system messages are dropped to fit before each LLM call (system messages and the latest message are always kept):

agent = RCrewAI::Agent.new(name: 'a', role: '...', goal: '...',
                           respect_context_window: true)

Window sizes come from RCrewAI::ContextWindow (with a conservative default for unknown models); headroom for the response is reserved from max_tokens. Off by default.

πŸ–ΌοΈ Multimodal Input

Pass images to a vision-capable model via task attachments. Local files are base64-encoded automatically; URLs pass through:

RCrewAI.configure { |c| c.llm_provider = :openai; c.openai_model = 'gpt-4o' }

task = RCrewAI::Task.new(
  name: 'describe', description: 'What is in this chart?', agent: agent,
  attachments: [
    { type: :image, path: 'chart.png' },
    { type: :image, url: 'https://example.com/photo.jpg' }
  ]
)

Supported on OpenAI and Azure; other providers raise a clear error when attachments are present.

πŸ“š Knowledge (RAG)

Ground agents in your own documents. Sources are chunked, embedded, and stored in an in-memory vector store; the most relevant chunks are injected into each task's prompt automatically.

kb = RCrewAI::Knowledge::Base.new(sources: [
  RCrewAI::Knowledge::StringSource.new('Our refund window is 30 days.'),
  RCrewAI::Knowledge::FileSource.new('docs/policy.txt'),
  RCrewAI::Knowledge::PdfSource.new('handbook.pdf'),
  RCrewAI::Knowledge::UrlSource.new('https://example.com/faq')
])

# Agent-level (role-specific) knowledge:
support = RCrewAI::Agent.new(name: 'support', role: '...', goal: '...', knowledge: kb)

# Or pass raw sources and let the agent build the base:
support = RCrewAI::Agent.new(name: 'support', role: '...', goal: '...',
                             knowledge_sources: [RCrewAI::Knowledge::StringSource.new('...')])

# Crew-level knowledge is shared with every agent:
crew = RCrewAI::Crew.new('support_crew', knowledge: kb)

Embeddings default to OpenAI's text-embedding-3-small. Use another provider with RCrewAI::Knowledge::Embedder.new(provider: :ollama) (also :azure, :google; :anthropic has no embeddings API), or pass any custom embedder: (anything responding to embed(texts)) / vector store to swap the backend.

🧠 Cognitive Memory

Agents remember what they've done and recall it semantically on future tasks. Memory is zero-config by default (in-memory, lexical recall); add an embedder for semantic recall and a SQLite store for persistence:

embedder = RCrewAI::Knowledge::Embedder.new
store    = RCrewAI::Memory::SqliteStore.new(path: '~/.rcrewai/memory.db')

agent = RCrewAI::Agent.new(
  name: 'engineer', role: '...', goal: '...',
  memory: { embedder: embedder, store: store }   # both optional
)
  • Semantic recall β€” with an embedder, an agent recalls conceptually related past work even when the wording differs (falls back to word-overlap without one).
  • Persistence β€” a SqliteStore makes memory survive restarts.
  • Memory types β€” agent.memory.short_term / long_term / entity / tool.
  • Scoping β€” memory is scoped per agent so a shared store doesn't cross-read.

Memory is best-effort: embedding failures fall back to lexical similarity, so it never breaks agent execution.

🌊 Flows

Beyond crews, RCrewAI has Flows β€” an event-driven workflow engine for orchestrating steps (and whole crews) with explicit branching and state:

class ArticleFlow < RCrewAI::Flow
  start :outline
  def outline
    state.sections = %w[intro body conclusion]
    state.sections.length
  end

  listen :outline
  def draft(section_count)
    state.words = section_count * 100
    state.words
  end

  router :draft
  def review(words)
    words >= 250 ? :publish : :expand
  end

  listen :publish
  def publish = state.status = 'published'

  listen :expand
  def expand = state.status = 'needs more work'
end

flow = ArticleFlow.new
flow.kickoff(inputs: { author: 'me' })
flow.state.status      # => "published"
flow.state.id          # => automatic UUID
  • start / listen / router wire methods into a graph; a listener receives its trigger's return value.
  • Combine triggers with and_(:a, :b) (all) and or_(:a, :b) (any).
  • State is a schemaless object with a UUID, seedable via kickoff(inputs:).
  • Persistence: pass state_store: (RCrewAI::Flow::FileStateStore.new(dir) or your own #save/#load) and call flow.restore(id) to resume.
  • Invoke a Crew inside any step, or pause with human_feedback('Approve?').

πŸ’‘ Examples

Hierarchical Team with Human Oversight

# Create a hierarchical crew with manager coordination
crew = RCrewAI::Crew.new("enterprise_team", process: :hierarchical)

# Manager agent coordinates the team
manager = RCrewAI::Agent.new(
  name: "project_manager",
  role: "Senior Project Manager", 
  goal: "Coordinate team execution efficiently",
  manager: true,
  allow_delegation: true
)

# Specialist agents with human-in-the-loop capabilities
data_analyst = RCrewAI::Agent.new(
  name: "data_analyst",
  role: "Senior Data Analyst",
  goal: "Analyze data with human validation",
  tools: [RCrewAI::Tools::SqlDatabase.new],
  human_input: true,                      # Enable human interaction
  require_approval_for_tools: true,       # Human approves SQL queries
  require_approval_for_final_answer: true # Human validates analysis
)

crew.add_agent(manager)
crew.add_agent(data_analyst)

# Execute with async/hierarchical coordination
results = crew.execute(async: true, max_concurrency: 2)

Async/Concurrent Execution

# Tasks that can run in parallel
research_task = RCrewAI::Task.new(
  name: "market_research",
  description: "Research market trends",
  async: true
)

analysis_task = RCrewAI::Task.new(
  name: "competitive_analysis", 
  description: "Analyze competitors",
  async: true
)

crew.add_task(research_task)
crew.add_task(analysis_task)

# Execute with parallel processing
results = crew.execute(
  async: true,
  max_concurrency: 4,
  timeout: 300
)

πŸ› οΈ CLI Usage

# Create a new crew
$ rcrewai new my_research_crew --process sequential

# Create agents with tools
$ rcrewai agent new researcher \
  --role "Senior Research Analyst" \
  --tools web_search,file_writer \
  --human-input

# Create tasks with dependencies  
$ rcrewai task new research \
  --description "Research latest AI developments" \
  --agent researcher \
  --async

# Run crews
$ rcrewai run --crew my_research_crew --async

πŸ“š Examples & Documentation

🎯 Use Cases

RCrewAI excels in scenarios requiring:

  • πŸ” Research & Analysis: Multi-source research with data correlation
  • πŸ“ Content Creation: Collaborative content development workflows
  • 🏒 Business Intelligence: Data analysis and strategic planning
  • πŸ› οΈ Development Workflows: Code analysis, testing, and documentation
  • πŸ“Š Data Processing: ETL workflows with validation
  • πŸ€– Customer Support: Intelligent routing and response generation
  • 🎯 Decision Making: Multi-criteria analysis with human oversight

πŸ—οΈ Architecture

RCrewAI provides a flexible, production-ready architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Crew Layer    β”‚    β”‚  Human Layer    β”‚    β”‚   Tool Layer    β”‚
β”‚                 β”‚    β”‚                 β”‚    β”‚                 β”‚
β”‚ β€’ Orchestration β”‚    β”‚ β€’ Approvals     β”‚    β”‚ β€’ Web Search    β”‚
β”‚ β€’ Process Types β”‚    β”‚ β€’ Guidance      β”‚    β”‚ β€’ File Ops      β”‚
β”‚ β€’ Async Exec    β”‚    β”‚ β€’ Reviews       β”‚    β”‚ β€’ SQL Database  β”‚
β”‚ β€’ Dependencies  β”‚    β”‚ β€’ Interventions β”‚    β”‚ β€’ Email         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                        β”‚                        β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚                 β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚   Agent Layer   β”‚    β”‚   LLM Layer     β”‚
              β”‚                 β”‚    β”‚                 β”‚
              β”‚ β€’ Reasoning     β”‚    β”‚ β€’ OpenAI        β”‚
              β”‚ β€’ Memory        β”‚    β”‚ β€’ Anthropic     β”‚
              β”‚ β€’ Tool Usage    β”‚    β”‚ β€’ Google        β”‚
              β”‚ β€’ Delegation    β”‚    β”‚ β€’ Azure         β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Rails Integration

rcrew RAILS

For Rails applications, use the rcrew RAILS gem (rcrewai-rails) (repo here) which provides:

  • πŸ—οΈ Rails Engine: Mountable engine with web UI for managing crews
  • πŸ’Ύ ActiveRecord Integration: Database persistence for agents, tasks, and executions
  • ⚑ Background Jobs: ActiveJob integration for async crew execution
  • 🎯 Rails Generators: Scaffolding for crews, agents, and tasks
  • 🌐 Web Dashboard: Monitor and manage your AI crews through a web interface
  • πŸ”§ Rails Configuration: Seamless integration with Rails configuration patterns
# Gemfile
gem 'rcrewai-rails'

# config/routes.rb
Rails.application.routes.draw do
  mount RcrewAI::Rails::Engine, at: '/rcrewai'
end

# Generate a new crew
rails generate rcrew_ai:crew marketing_crew

# Create persistent agents and tasks through Rails models
crew = RcrewAI::Rails::Crew.create!(name: "Content Team", description: "AI content generation")
agent = crew.agents.create!(name: "writer", role: "Content Writer", goal: "Create engaging content")

Install rcrew RAILS: gem install rcrewai-rails

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

πŸ“„ License

RCrewAI is released under the MIT License.

πŸ“ž Support

🌟 Star History

Star History Chart


Made with ❀️ by the RCrewAI community