agentbreeder

Sidecar — Cross-Cutting Concerns Layer

Auto-injected Go binary that handles tracing, cost attribution, guardrails, A2A, and MCP for every deployed agent.

Sidecar — Cross-Cutting Concerns Layer

The sidecar is a single Go binary auto-injected next to every AgentBreeder agent. The agent talks to it over localhost; the sidecar handles all of the boring-but-mandatory infrastructure work — tracing, cost attribution, guardrails, A2A, MCP, and bearer-token auth — so language SDKs stay thin.

One binary, every language, every cloud.


When the sidecar is injected

The deploy pipeline auto-injects rajits/agentbreeder-sidecar:<version> whenever your agent.yaml declares any of:

  • guardrails: — a list of egress rules (PII, content filter, custom)
  • MCP tools: — any tools: entry that resolves to an MCP server
  • a2a: — an A2A peer block

If none of these are present the sidecar is not injected — the agent runs alone, and there's no overhead for simple agents.

Auto-injection coverage in v2.0

v2.0 wires sidecar auto-injection into Docker Compose, GCP Cloud Run, and AWS ECS Fargate deployers. AWS App Runner, Azure Container Apps, and Kubernetes deployers will land auto-injection in v2.x — for those targets today, run the sidecar as a separate task/container and point AGENTBREEDER_SIDECAR_AGENT_URL at your agent. Tracking issue: open one at agentbreeder/agentbreeder/issues if you need a specific target prioritised.

To override behaviour locally, set AGENTBREEDER_SIDECAR=disabled in the environment. The injection helper short-circuits and the agent runs solo regardless of agent.yaml.

agent.yaml — triggers sidecar injection
name: support-agent
version: 1.0.0
team: customer-success
owner: alice@company.com

model:
  primary: claude-sonnet-4

framework: langgraph

# Any of these three triggers sidecar injection
guardrails:
  - pii_detection
  - content_filter

tools:
  - ref: tools/zendesk-mcp        # MCP tool — triggers injection

# (a2a:) block also triggers injection

Topology

┌──────── Pod / Task / Cloud Run revision ─────────┐
│                                                  │
│  ┌─────────────┐   localhost   ┌──────────────┐  │
│  │  user agent │ ◄───────────► │   sidecar    │  │
│  │  (any lang) │   :8080 in    │  (Go binary) │  │
│  │             │   :9090 a2a   │              │  │
│  │             │   :9091 mcp   │  → OTel      │  │
│  └─────────────┘   :9092 cost  │  → cost svc  │  │
│       ▲                        │  → guardrail │  │
│       │ inbound :8080          └──────────────┘  │
└───────┼──────────────────────────────────────────┘

   external traffic (deployer ingress → sidecar → agent)

External traffic hits the sidecar on :8080. The sidecar:

  1. Validates the bearer token (AGENT_AUTH_TOKEN)
  2. Runs egress guardrails on the request body
  3. Forwards the (possibly redacted) request to the agent on :8081

The agent uses localhost helper endpoints to send A2A calls, talk to MCP servers, and emit cost events without re-implementing any of that logic per language.


Endpoints

Inbound (:8080)

PathMethodAuthDescription
/healthGETopenLiveness probe
/openapi.jsonGETopenSelf-describing schema
/**bearerForwarded to the agent on AGENTBREEDER_SIDECAR_AGENT_URL after guardrails

Local helpers (127.0.0.1:9090)

PathMethodDescription
/a2a/{peer}POSTJSON-RPC 2.0 send to a configured A2A peer
/mcp/{server}POSTJSON-RPC passthrough to a configured MCP server (HTTP / SSE)
/costPOSTRecord a cost/token event in the AgentBreeder API (writes both costs + audit_log tables)
/healthGETLiveness for the local helpers

Guardrails

The sidecar ships with built-in PII rules — SSN, credit-card, email — that run on every egress. You can extend them by mounting a YAML file at /etc/agentbreeder/sidecar.yaml:

sidecar.yaml
guardrails:
  - name: ssn-block
    type: regex
    pattern: '\b\d{3}-\d{2}-\d{4}\b'
    action: block             # block | redact | warn (default redact)
  - name: profanity
    type: keyword
    pattern: "darn,heck"
    action: redact
    replace: "[CENSORED]"

Actions:

  • block — short-circuits and returns 403; the agent never sees the request.
  • redact — rewrites the request body before forwarding (default).
  • warn — records a violation but lets the request through.

The default rules run first; user rules run after and can layer on top.


Calling A2A peers

Configure peers in sidecar.yaml:

a2a_peers:
  research-agent: https://research.run.app

  # Per-peer bearer token: peer-token@@<url>
  finance-agent: finance-tok@@https://finance.run.app

Then from your agent, regardless of language, just POST to localhost:

from a Python agent
import httpx

resp = httpx.post(
    "http://127.0.0.1:9090/a2a/research-agent",
    json={"method": "tasks/send", "params": {"message": "summarise X"}},
)
result = resp.json()["result"]

The wire format matches engine/a2a/protocol.py exactly so Python and Go peers interoperate without a shim.


Calling MCP servers

mcp_servers:
  docs:
    transport: http
    url: https://docs.example.com/mcp
from a Python agent
resp = httpx.post(
    "http://127.0.0.1:9090/mcp/docs",
    json={"method": "tools/list", "params": {}},
)

v1 supports HTTP / SSE upstream MCP servers. Stdio transport is deferred to a follow-up — see the TODO in sidecar/internal/mcp/mcp.go.


Cost events

Every LLM call should emit a cost event so the registry stays attribution-accurate. Either call the local sidecar helper:

httpx.post("http://127.0.0.1:9090/cost", json={
    "model": "claude-sonnet-4",
    "input_tokens": 1024,
    "output_tokens": 256,
    "cost_usd": 0.0038,
    "trace_id": current_trace_id(),
})

…or rely on language-SDK middleware to emit it for you (Python / TS SDK ship this; Go / Kotlin / Rust SDKs ship in Track I).

The sidecar writes one row to the costs table and a corresponding cost.recorded entry to the audit log per event.


Environment variables

VarRequiredDefaultNotes
AGENT_NAMECanonical agent identifier
AGENT_VERSIONPopulated automatically by the deployer
AGENT_AUTH_TOKENBearer token validated on inbound :8080
AGENTBREEDER_SIDECARenabledSet to disabled / off / false / 0 to skip injection
AGENTBREEDER_SIDECAR_AGENT_URLhttp://127.0.0.1:8081Where to forward inbound traffic
OTEL_EXPORTER_OTLP_ENDPOINTOTLP/HTTP base URL. When unset, span export is a no-op
OTEL_EXPORTER_OTLP_HEADERSComma-separated k=v pairs
AGENTBREEDER_API_URLAPI base for cost emission
AGENTBREEDER_API_TOKENBearer token used when calling the AgentBreeder API

Local development

To run an agent without the sidecar:

export AGENTBREEDER_SIDECAR=disabled
agentbreeder deploy --target local

The deployer's should_inject() helper honours this env var and the sidecar container is skipped entirely.

To run the sidecar locally with an agent:

docker run --rm \
  -e AGENT_NAME=demo \
  -e AGENT_AUTH_TOKEN=$(openssl rand -hex 16) \
  -e AGENTBREEDER_SIDECAR_AGENT_URL=http://host.docker.internal:8081 \
  -p 8080:8080 \
  rajits/agentbreeder-sidecar:latest

A complete docker-compose example lives at sidecar/examples/compose/.


Source

The sidecar source is in the top-level sidecar/ directory of the agentbreeder repo. It's a self-contained Go module — no Python dependency.

Build:

cd sidecar
go test ./... -cover
go build -o sidecar ./cmd/sidecar

# Multi-arch image
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag rajits/agentbreeder-sidecar:dev \
  -f Dockerfile .

The sidecar binary is built in CI and published as rajits/agentbreeder-sidecar:<version> on each AgentBreeder platform release.

On this page