ruby, agent development, api design, open source, distributed systems,

A2A Ruby Gem: Agent-to-Agent Communication Made Simple

Sebastian Schkudlara Sebastian Schkudlara Follow Sep 16, 2025 · 16 mins read
A2A Ruby Gem: Agent-to-Agent Communication Made Simple
Share this

A2A Ruby Gem: Agent-to-Agent Communication Made Simple

Remember when APIs were just REST endpoints that returned JSON and we called it a day? Those were simpler times. Now we’re living in the age of agents talking to agents, and frankly, it’s both exciting and slightly terrifying—like watching your smart home devices gossip about your Netflix habits.

Enter the A2A Ruby gem—our fresh implementation of Google’s Agent2Agent protocol that makes building conversational agents as easy as writing a regular Ruby class. No PhD in distributed systems required, though a sense of humor about talking computers definitely helps.


What the Heck is A2A?

Agent2Agent (A2A) is Google’s protocol for—you guessed it—agents talking to other agents. Think of it as a standardized way for AI services to have polite conversations instead of just screaming JSON at each other across the internet.

The protocol is built on JSON-RPC 2.0 (because apparently we needed to make RPC cool again) and includes all the grown-up features you’d expect:

  • Agent Discovery via “Agent Cards” (like business cards, but for robots)
  • Streaming Responses for when your agent is chatty
  • Task Management with proper lifecycle handling
  • Security that doesn’t make you cry
  • Multiple Transports because variety is the spice of distributed life

Why Another Ruby Gem?

Great question! While Google provides SDKs for Python, JavaScript, and Java, the Ruby ecosystem was feeling a bit left out of the agent party. So we built the A2A Ruby gem to bring first-class A2A support to Ruby applications.

But this isn’t just a “me too” implementation. We’ve designed it with Ruby developers in mind:

# This is all you need to create an A2A agent
class MyAgent
  include A2A::Server::Agent
  
  a2a_method "greet" do |params|
    { message: "Hello, #{params['name']}!" }
  end
end

That’s it. No XML configuration files, no annotation processors, no sacrificial offerings to the framework gods. Just Ruby being Ruby.


The Gem in Action: Real Examples

Let’s look at some actual agents built with the gem, because examples are worth a thousand architecture diagrams.

The Dice Agent: When Probability Meets Personality

class DiceAgent
  include A2A::Server::Agent
  
  a2a_capability "dice_rolling" do
    method "roll_dice"
    description "Roll dice and track statistics"
    tags ["gaming", "probability", "fun"]
  end
  
  a2a_method "roll_dice" do |params|
    sides = params['sides'] || 6
    count = params['count'] || 1
    
    rolls = count.times.map { rand(1..sides) }
    
    {
      rolls: rolls,
      sum: rolls.sum,
      timestamp: Time.now.utc.iso8601,
      message: "🎲 You rolled: #{rolls.join(', ')}"
    }
  end
  
  # Natural language processing? Sure, why not!
  a2a_method "process_natural_language" do |params|
    text = params['text'].downcase
    
    if text.match?(/roll|dice/)
      # Parse "roll two 20-sided dice" into actual parameters
      sides = text.match(/(\d+)[- ]?sided?/)&.captures&.first&.to_i || 6
      count = text.match(/(\d+)\s+dice/)&.captures&.first&.to_i || 1
      
      roll_dice('sides' => sides, 'count' => count)
    else
      { message: "I can help you roll dice! Try 'roll two 6-sided dice'" }
    end
  end
end

This agent doesn’t just roll dice—it understands natural language, tracks statistics, and even adds emoji because why should humans have all the fun?

The Weather Agent: Meteorology Meets Conversation

class WeatherAgent
  include A2A::Server::Agent
  
  a2a_capability "weather_info" do
    method "get_current_weather"
    description "Get current weather conditions"
    input_schema type: "object", 
                 properties: { location: { type: "string" } }
  end
  
  a2a_method "get_current_weather" do |params|
    location = params['location']
    weather_data = WeatherService.fetch(location)
    
    {
      location: location,
      temperature: weather_data[:temp],
      condition: weather_data[:condition],
      message: "🌤️ It's #{weather_data[:temp]}°C and #{weather_data[:condition]} in #{location}"
    }
  end
  
  # This agent also speaks human
  a2a_method "process_natural_language" do |params|
    text = params['text']
    
    # Extract location from "What's the weather in Tokyo?"
    if match = text.match(/weather.*?in\s+([a-zA-Z\s,]+)/i)
      location = match[1].strip
      get_current_weather('location' => location)
    else
      { message: "Ask me about the weather! Try 'What's the weather in London?'" }
    end
  end
end

The Magic Behind the Scenes

JSON-RPC 2.0 with Style

The gem handles all the JSON-RPC plumbing so you don’t have to think about it:

# Your agent method
a2a_method "echo" do |params|
  { message: params['text'] }
end

# Gets called via JSON-RPC like this:
{
  "jsonrpc": "2.0",
  "method": "echo",
  "params": { "text": "Hello, World!" },
  "id": 1
}

# Returns this:
{
  "jsonrpc": "2.0",
  "result": { "message": "Hello, World!" },
  "id": 1
}

Agent Cards: The Business Cards of the Future

Every agent automatically generates an “Agent Card” that describes its capabilities:

{
  "name": "Weather Agent",
  "description": "Provides weather information and forecasts",
  "version": "1.0.0",
  "capabilities": [
    {
      "name": "weather_info",
      "methods": ["get_current_weather", "get_forecast"],
      "description": "Weather data and forecasting"
    }
  ],
  "connection_info": {
    "endpoint": "https://weather-agent.example.com/a2a/rpc",
    "transport": "JSONRPC"
  }
}

This lets other agents discover what your agent can do without having to read documentation (because let’s be honest, who reads documentation?).

Streaming Support for Chatty Agents

Some agents have a lot to say. The gem supports streaming responses:

a2a_method "stream_data", streaming: true do |params|
  Enumerator.new do |yielder|
    10.times do |i|
      yielder << { count: i, message: "Processing step #{i}" }
      sleep 0.1  # Simulate work
    end
  end
end

Rails Integration That Just Works

If you’re building Rails applications (and let’s face it, you probably are), the gem includes a Rails engine:

# In your Gemfile
gem 'a2a-ruby'

# In config/routes.rb
mount A2A::Engine => "/a2a"

# In your controller
class MyAgentController < ApplicationController
  include A2A::Server::Agent
  
  a2a_method "hello" do |params|
    { message: "Hello from Rails!" }
  end
end

Boom. Your Rails app is now an A2A agent with endpoints at /a2a/rpc and /a2a/agent-card.


The Developer Experience We Actually Want

Configuration That Makes Sense

A2A.configure do |config|
  config.protocol_version = "0.3.0"
  config.default_transport = "JSONRPC"
  config.streaming_enabled = true
  config.log_level = :info
  
  # Because security matters
  config.authentication_required = true
  config.rate_limiting_enabled = true
end

Error Handling That Doesn’t Suck

a2a_method "might_fail" do |params|
  raise A2A::Errors::InvalidParams, "Missing required field" unless params['required_field']
  
  # Your logic here
end

# Automatically becomes a proper JSON-RPC error response:
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Missing required field"
  },
  "id": 1
}

Testing That Actually Works

RSpec.describe MyAgent do
  include A2A::Testing::Helpers
  
  it "greets users properly" do
    response = call_a2a_method("greet", name: "Alice")
    
    expect(response).to be_a2a_success
    expect(response['result']['message']).to eq("Hello, Alice!")
  end
end

Real-World Use Cases

Microservices That Talk

Instead of REST APIs between services, use A2A for richer communication:

# User service
class UserAgent
  a2a_method "get_user_profile" do |params|
    user = User.find(params['user_id'])
    { profile: user.to_h, preferences: user.preferences }
  end
end

# Recommendation service  
class RecommendationAgent
  a2a_method "get_recommendations" do |params|
    # Call the user service
    user_client = A2A::Client::HttpClient.new("https://user-service/a2a")
    profile = user_client.call("get_user_profile", user_id: params['user_id'])
    
    # Generate recommendations based on profile
    recommendations = RecommendationEngine.generate(profile['preferences'])
    { recommendations: recommendations }
  end
end

AI Agent Orchestration

Build systems where AI agents collaborate:

class OrchestratorAgent
  a2a_method "process_complex_request" do |params|
    # Break down the request
    tasks = TaskPlanner.plan(params['request'])
    
    results = tasks.map do |task|
      agent_url = AgentRegistry.find_agent_for(task.type)
      client = A2A::Client::HttpClient.new(agent_url)
      client.call(task.method, task.params)
    end
    
    # Combine results
    FinalProcessor.combine(results)
  end
end

Customer Service Automation

class CustomerServiceAgent
  a2a_method "handle_inquiry" do |params|
    inquiry = params['inquiry']
    
    # Route to appropriate specialist agent
    if inquiry.match?(/billing|payment/)
      billing_agent.call("handle_billing_inquiry", inquiry: inquiry)
    elsif inquiry.match?(/technical|bug/)
      tech_agent.call("handle_tech_support", inquiry: inquiry)
    else
      general_agent.call("handle_general_inquiry", inquiry: inquiry)
    end
  end
end

Performance and Production Readiness

Built for Scale

The gem includes production-ready features out of the box:

  • Connection pooling for client connections
  • Rate limiting with Redis backend
  • Comprehensive logging with structured output
  • Metrics collection for monitoring
  • Health checks for load balancers
  • Graceful shutdown handling

Benchmarks That Matter

In our testing, the gem handles:

  • 1000+ requests/second on modest hardware
  • Sub-10ms latency for simple methods
  • Efficient memory usage with connection reuse
  • Proper backpressure handling under load

Monitoring Integration

A2A.configure do |config|
  config.metrics_enabled = true
  config.metrics_backend = :prometheus
  
  # Custom metrics
  config.on_method_call do |method_name, duration, success|
    MyMetrics.record("a2a_method_duration", duration, method: method_name)
    MyMetrics.increment("a2a_method_calls", method: method_name, success: success)
  end
end

Getting Started: Your First Agent in 5 Minutes

Installation

gem install a2a-ruby
# or add to Gemfile
gem 'a2a-ruby'

Hello World Agent

# hello_agent.rb
require 'a2a'

class HelloAgent
  include A2A::Server::Agent
  
  a2a_method "greet" do |params|
    name = params['name'] || 'World'
    { message: "Hello, #{name}!" }
  end
end

# Start the server
agent = HelloAgent.new
server = A2A::Server::HttpServer.new(agent, port: 3000)
server.start

Test It

curl -X POST http://localhost:3000/a2a/rpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "greet",
    "params": {"name": "Ruby Developer"},
    "id": 1
  }'

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "message": "Hello, Ruby Developer!"
  },
  "id": 1
}

The Road Ahead

What’s Coming Next

  • gRPC transport for high-performance scenarios
  • WebSocket support for real-time communication
  • Agent discovery service for dynamic agent networks
  • Visual agent builder for non-developers
  • More authentication schemes (OAuth2, JWT, mTLS)

Community and Contributions

The gem is open source and we’re actively looking for contributors. Whether you want to:

  • Add new transport protocols
  • Improve documentation
  • Build example agents
  • Report bugs (please do!)
  • Suggest features

Check out our GitHub repository and join the conversation.


Why This Matters

We’re at the beginning of the agent economy. Soon, every application will have some form of AI agent capability, and these agents will need to work together. The A2A protocol provides a standard way for this to happen, and the A2A Ruby gem makes it accessible to the Ruby community.

Think of it as building the roads for the agent economy. Sure, you could build your own proprietary communication protocol, but why would you when there’s a perfectly good highway system available?

The Bigger Picture

This isn’t just about Ruby or even just about agents. It’s about creating interoperable systems that can evolve and scale. When your customer service agent can seamlessly hand off to a billing agent, which can then coordinate with a fulfillment agent, you’ve built something powerful.

And when all of this happens through standardized protocols with proper error handling, authentication, and monitoring, you’ve built something production-ready.


Conclusion: Agents All the Way Down

The A2A Ruby gem represents our bet on the future of distributed systems. Instead of services that just exchange data, we’re building services that can have conversations.

Your Ruby applications can now:

  • Expose their capabilities through standardized agent cards
  • Communicate naturally with other agents
  • Handle complex workflows through agent orchestration
  • Scale gracefully with proper production features

And the best part? It feels like writing regular Ruby code, because that’s exactly what it is.

So go ahead, give your Ruby apps a voice. Build agents that roll dice, predict weather, or orchestrate complex business processes. The A2A Ruby gem makes it all possible, and frankly, it’s pretty fun too.

After all, in a world where everything is becoming an agent, shouldn’t your Ruby code get to join the conversation?


Ready to build your first agent? Check out the A2A Ruby gem documentation and start building the future of agent communication today.

About the Author

Sebastian Schkudlara is a Software Architect with over 19 years of experience in designing scalable, cloud-native platforms and secure, agentic AI systems. He specializes in OAuth-based identity frameworks, large language model orchestration, and event-driven architectures for enterprise environments. Sebastian’s expertise consistently bridges the gap between theoretical AI capabilities and practical enterprise implementation, with particular emphasis on security, scalability, and operational excellence.

🔗 Connect: LinkedIn

Sebastian Schkudlara
Written by Sebastian Schkudlara Follow
Hi, I am Sebastian Schkudlara, the author of Jevvellabs. I hope you enjoy my blog!