Agent-to-Agent (A2A) Networking
SkillAI & modelsExpose agents as A2A JSON-RPC servers discoverable via Agent Cards, and connect agents to remote A2A agents using the client discovery and capability-matching APIs.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Agent-to-Agent (A2A) Networking skill
What this skill tells your AI
The instructions your AI receives, as published by tylerjrbuell/reactive-agents-ts in apps/docs/skills/a2a-agent-networking/SKILL.md and read by ahel’s review.
Agent objective
Produce a builder with .withA2A() configured to expose an agent as an A2A server, or connect to remote A2A agents using the client APIs from @reactive-agents/a2a.
When to load this skill
- Exposing an agent as a remotely callable A2A service
- Connecting a lead agent to remote specialist agents at different URLs
- Discovering available agents in a network via Agent Cards
- Building agent microservices that communicate over HTTP
Implementation baseline
Exposing an agent as an A2A server
import { ReactiveAgents } from "@reactive-agents/runtime";
const agent = await ReactiveAgents.create()
.withName("specialist")
.withProvider("anthropic")
.withReasoning({ defaultStrategy: "adaptive", maxIterations: 10 })
.withTools({ allowedTools: ["web-search", "http-get", "checkpoint"] })
.withA2A({ port: 8000 }) // starts A2A HTTP server on port 8000
.build();
// Agent is now discoverable at:
// GET http://localhost:8000/.well-known/agent.json (Agent Card)
// POST http://localhost:8000/rpc (JSON-RPC 2.0)
Connecting from a lead agent
const lead = await ReactiveAgents.create()
.withProvider("anthropic")
.withReasoning({ defaultStrategy: "plan-execute-reflect", maxIterations: 20 })
.withRemoteAgent("specialist", "http://specialist-service:8000")
// Registers the remote A2A agent as a callable tool named "specialist"
.withTools({ allowedTools: ["specialist", "checkpoint", "final-answer"] })
.build();
Key patterns
withA2A() — expose as A2A server
.withA2A()
// Default port: 3000, basePath: "/"
// Endpoints:
// /.well-known/agent.json → Agent Card
// /rpc → JSON-RPC 2.0 task endpoint
.withA2A({ port: 8000 })
// Custom port
.withA2A({ port: 8000, basePath: "/api/agents" })
// Agent Card at: http://localhost:8000/api/agents/.well-known/agent.json
// RPC at: http://localhost:8000/api/agents/rpc
A2A client — discover and call agents
import {
A2AClient,
createA2AClient,
discoverAgent,
discoverMultipleAgents,
matchCapabilities,
findBestAgent,
} from "@reactive-agents/a2a";
import { Effect } from "effect";
// Discover a single agent's card
const program = Effect.gen(function* () {
const card = yield* discoverAgent("http://specialist:8000");
console.log("Agent name:", card.name);
console.log("Skills:", card.skills);
});
// Discover multiple agents
const multi = Effect.gen(function* () {
const cards = yield* discoverMultipleAgents([
"http://researcher:8001",
"http://coder:8002",
"http://reviewer:8003",
]);
// Find best match for a capability
const best = findBestAgent(cards, { capability: "code-review" });
});
// Direct A2A client call
const call = Effect.gen(function* () {
const client = yield* A2AClient;
const result = yield* client.send({
agentCardUrl: "http://specialist:8000/.well-known/agent.json",
message: { role: "user", content: "Analyze this dataset..." },
});
console.log(result.output);
});
Generating Agent Cards
import { generateAgentCard, toolsToSkills } from "@reactive-agents/a2a";
const card = generateAgentCard({
name: "Data Analyst",
description: "Analyzes datasets and produces statistical summaries",
skills: toolsToSkills(myTools), // converts ToolDefinition[] to A2A skill format
version: "1.0.0",
url: "http://analyst-agent:8000",
});
A2A vs withRemoteAgent()
Two ways to connect to remote agents:
// Option 1: withRemoteAgent() on the builder (simpler — agent-as-tool pattern)
.withRemoteAgent("analyst", "http://analyst:8000")
// The remote agent appears as a tool named "analyst" in the LLM's tool list.
// No client code needed — the framework handles the A2A protocol.
// Option 2: A2AClient directly (more control — for custom orchestration)
import { A2AClient } from "@reactive-agents/a2a";
// Use when you need capability discovery, load balancing, or custom retry logic.
A2AOptions reference
| Field | Type | Default | Notes |
|---|---|---|---|
port | number | 3000 | HTTP port for the A2A server |
basePath | string | "/" | Base path for A2A endpoints |
Endpoints exposed by withA2A()
| Endpoint | Method | Description |
|---|---|---|
<basePath>/.well-known/agent.json | GET | Agent Card (capabilities, skills, metadata) |
<basePath>/rpc | POST | JSON-RPC 2.0 task execution endpoint |
Pitfalls
.withA2A()starts an HTTP server — the agent process must stay alive for the server to serve requests (combine with.withGateway()for persistent agents)- The A2A server is started during
.build()— port conflicts will throw at build time, not at call time withRemoteAgent()connects to the remote agent at build time to fetch its Agent Card — the remote agent must be up when.build()is called- Agent Cards are generated from the agent's name, description, and registered tools — populate
.withName()and the system prompt for a meaningful card - A2A uses JSON-RPC 2.0 over HTTP — ensure firewalls and network policies allow traffic between agent services on the configured ports
- Each agent has its own A2A server instance —
portmust be unique per agent process to avoid conflicts
Signals
- GitHub stars
- 27
- Forks
- 4
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
a2a-agent-networking- Source
- github.com/tylerjrbuell/reactive-agents-ts