forked from cleveragents/cleveragents-core
289 lines
17 KiB
Markdown
289 lines
17 KiB
Markdown
---
|
|
adr_number: 26
|
|
title: Agent-to-Agent Protocol (A2A)
|
|
status_history:
|
|
- - '2026-02-17'
|
|
- Proposed
|
|
- Jeffrey Phillips Freeman
|
|
- - '2026-02-17'
|
|
- Accepted
|
|
- Jeffrey Phillips Freeman
|
|
tier: 4
|
|
authors:
|
|
- Jeffrey Phillips Freeman
|
|
superseded_by: null
|
|
related_adrs:
|
|
- number: 1
|
|
title: Layered Architecture
|
|
relationship: A2A defines the fundamental boundary between the Presentation and Application layers in the four-layer architecture
|
|
- number: 6
|
|
title: Plan Lifecycle
|
|
relationship: A2A extension methods expose the full plan lifecycle (use, execute, apply, cancel, correct, rollback) to all clients
|
|
- number: 20
|
|
title: Session Model
|
|
relationship: A2A message operations (message/send, message/stream) map directly to SessionWorkflow operations
|
|
- number: 21
|
|
title: CLI and Output Rendering
|
|
relationship: Every CLI command maps to an A2A method (standard or extension); the CLI is a thin rendering layer over A2A
|
|
- number: 23
|
|
title: Server Mode
|
|
relationship: A2A is the sole client-server protocol; server mode uses A2A over HTTP, local mode uses A2A JSON-RPC over stdio
|
|
- number: 25
|
|
title: Observability and Logging
|
|
relationship: A2A task update events deliver structured plan state changes and tool call events to subscribed clients
|
|
- number: 27
|
|
title: Language Server Protocol (LSP) Integration
|
|
relationship: LSP servers are Infrastructure-layer components attached to actors; the IDE plugin (Presentation layer) communicates through A2A independently of LSP
|
|
- number: 47
|
|
title: A2A Standard Adoption
|
|
relationship: ADR-047 defines the adoption of the external A2A standard that this ADR's protocol boundary implements
|
|
- number: 48
|
|
title: Server Application Architecture
|
|
relationship: ADR-048 defines the server that implements the A2A endpoint; this ADR defines the protocol boundary role
|
|
acceptance:
|
|
votes_for:
|
|
- voter: Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>
|
|
comment: A2A provides the standardized agent-to-agent communication layer needed for multi-actor orchestration
|
|
votes_against: []
|
|
abstentions: []
|
|
---
|
|
## Context
|
|
|
|
CleverAgents is accessed through multiple presentation-layer clients — CLI, TUI, and an IDE plugin — and can operate in both local (single-process) and server (multi-user) modes. Without a shared, versioned contract between clients and the backend, each client would require bespoke integration code that drifts from the core domain model, making interoperability fragile and third-party client development impractical. The architecture needs a single protocol surface that all clients rely on regardless of deployment mode.
|
|
|
|
## Decision Drivers
|
|
|
|
- Multiple presentation-layer clients (CLI, TUI, IDE plugin) must share a single, versioned contract to avoid bespoke integration code that drifts from the core domain model
|
|
- Local (in-process) and server (remote) deployment modes must expose identical operational semantics to all clients
|
|
- Third-party client development must be practical without knowledge of internal domain or infrastructure services
|
|
- Long-running operations (plan execution, tool invocations) require real-time streaming with causal ordering guarantees
|
|
- The protocol must support backward-compatible evolution so existing clients are not broken by new features
|
|
- Alignment with the emerging agent interoperability ecosystem is preferred over a bespoke protocol
|
|
|
|
## Decision
|
|
|
|
CleverAgents adopts the **Agent-to-Agent (A2A) Protocol** — the open standard from [a2a-protocol.org](https://a2a-protocol.org) — as the **sole** communication protocol for all client-to-backend interaction. A2A is built on **JSON-RPC 2.0** (with additional gRPC and REST bindings available) and provides standard operations for agent communication plus an extensibility mechanism for platform-specific operations. In local mode A2A flows over **stdio** via the JSON-RPC binding (agent as subprocess); in server mode over **HTTP**.
|
|
|
|
## Design
|
|
|
|
### Architectural Role
|
|
|
|
A2A defines the **fundamental boundary between the Presentation and Application layers** in the CleverAgents layered architecture (ADR-001). Every arrow from a Presentation-layer component (CLI, TUI, IDE plugin, A2A server endpoint) to the Application-layer Service Facade represents an A2A operation. No Presentation-layer module is permitted to bypass A2A and access Domain or Infrastructure services directly.
|
|
|
|
This boundary role makes A2A the single most architecturally significant protocol in the system — MCP and Agent Skills plug into the Infrastructure and Domain layers respectively, LSP provides actor-attached language intelligence in the Infrastructure layer (see ADR-027), but A2A is the protocol surface through which *every* client operation flows.
|
|
|
|
### Agent Discovery: Agent Card
|
|
|
|
A2A introduces **Agent Cards** — JSON metadata documents served at `/.well-known/agent.json` — that describe an agent's identity, capabilities, skills, supported protocol bindings, authentication requirements, and extensions. The CleverAgents Agent Card declares:
|
|
|
|
- **Skills**: Plan lifecycle, registry CRUD, context management, entity sync, namespace management, diagnostics
|
|
- **Extensions**: `_cleveragents/` platform-specific methods (declared via the A2A extension mechanism with URI `urn:cleveragents:extensions:v1`)
|
|
- **Supported interfaces**: `jsonrpc` (primary), optionally `rest`
|
|
- **Security schemes**: OAuth2, API key, or HTTP bearer — published in the Agent Card so clients can authenticate without protocol-level handshakes
|
|
|
|
In server mode, the Agent Card is served at the well-known URI. An authenticated extended Agent Card with additional detail is available via the `getExtendedAgentCard` operation. In local mode, the Agent Card is provided during initialization.
|
|
|
|
### Protocol Scope
|
|
|
|
A2A communication is organized into two categories:
|
|
|
|
**Standard A2A operations** (defined by the external specification) handle the core agent interaction lifecycle:
|
|
|
|
| Operation Category | Operations | Service(s) |
|
|
|-------------------|-----------|------------|
|
|
| **Messaging** | `message/send`, `message/stream` | `SessionWorkflow`, `PlanService` |
|
|
| **Task lifecycle** | `tasks/get`, `tasks/list`, `tasks/cancel` | `TaskService` |
|
|
| **Task subscriptions** | `tasks/subscribe` | `TaskService`, event delivery |
|
|
| **Push notifications** | `pushNotificationConfig/create`, `get`, `list`, `delete` | Notification service |
|
|
| **Discovery** | `getExtendedAgentCard` | Agent Card service |
|
|
|
|
**CleverAgents extension methods** (`_cleveragents/`-prefixed per the A2A extensibility mechanism) handle platform operations:
|
|
|
|
| Extension Group | Methods | Service(s) |
|
|
|-----------------|---------|------------|
|
|
| **Plan lifecycle** | `_cleveragents/plan/use`, `execute`, `apply`, `cancel`, `status`, `tree`, `explain`, `correct`, `diff`, `artifacts`, `prompt`, `rollback`, `list` | `PlanService`, `PlanLifecycle`, `CorrectionFlow` |
|
|
| **Registries** | `_cleveragents/registry/{entity}/list`, `show`, `add`, `update`, `remove` | `ActorService`, `ToolService`, `SkillService`, `ResourceService`, `ProjectService` |
|
|
| **Context** | `_cleveragents/context/show`, `inspect`, `simulate`, `set` | `ContextService` |
|
|
| **Sync** | `_cleveragents/sync/pull`, `push`, `status` | `SyncService` |
|
|
| **Namespace** | `_cleveragents/namespace/list`, `show`, `members` | `NamespaceService` |
|
|
| **Health** | `_cleveragents/health/check`, `_cleveragents/diagnostics/run` | Health/diagnostic services |
|
|
|
|
Every CLI command maps to an A2A operation. When a user runs `agents plan status <ID>`, the CLI sends a `_cleveragents/plan/status` JSON-RPC request through the active transport and renders the response.
|
|
|
|
### Wire Format: JSON-RPC 2.0
|
|
|
|
The primary A2A protocol binding uses JSON-RPC 2.0 (A2A specification Section 9):
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"method": "_cleveragents/plan/status",
|
|
"params": { "plan_id": "01HXRCF1..." }
|
|
}
|
|
```
|
|
|
|
**Successful response:**
|
|
```json
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"result": { "plan_id": "01HXRCF1...", "phase": "execute", "state": "running" }
|
|
}
|
|
```
|
|
|
|
**Error response:**
|
|
```json
|
|
{
|
|
"jsonrpc": "2.0",
|
|
"id": 1,
|
|
"error": { "code": -32001, "message": "Plan not found", "data": { "plan_id": "01HXRCF1..." } }
|
|
}
|
|
```
|
|
|
|
### Transport Modes
|
|
|
|
A2A is **transport-agnostic** at the specification level, defining abstract operations with multiple protocol bindings. CleverAgents uses the JSON-RPC binding (A2A Section 9) with two transports:
|
|
|
|
**Local Mode — A2A JSON-RPC over stdio**
|
|
|
|
```
|
|
CLI ──stdio──→ Agent Subprocess ──→ A2aLocalFacade ──→ ServiceFacade.method()
|
|
```
|
|
|
|
The client spawns the agent as a subprocess. JSON-RPC messages flow over stdin/stdout. Extension methods are intercepted by `A2aLocalFacade` and routed to in-process Application-layer services. No network, no authentication.
|
|
|
|
**Server Mode — A2A JSON-RPC over HTTP**
|
|
|
|
```
|
|
CLI ──HTTP──→ CleverAgents A2A Server ──→ ServiceFacade.method()
|
|
```
|
|
|
|
The client connects to the CleverAgents server via the A2A SDK's HTTP transport. All operations (standard + extensions) flow through the single A2A JSON-RPC 2.0 endpoint. Authentication uses the security schemes declared in the Agent Card.
|
|
|
|
**Architectural enforcement of transport parity:**
|
|
|
|
- The same A2A test suite runs over both transports (contract tests).
|
|
- No Presentation-layer module imports from Infrastructure (import-linter CI checks).
|
|
- The Service Facade is the sole Application-layer entry point from Presentation.
|
|
|
|
### Streaming
|
|
|
|
A2A streaming uses **Server-Sent Events (SSE)** via the `message/stream` operation. The stream delivers typed events:
|
|
|
|
| Event Type | Emitted When |
|
|
|-----------|-------------|
|
|
| `TaskStatusUpdateEvent` | Task state changes (submitted → working → completed, etc.) |
|
|
| `TaskArtifactUpdateEvent` | Agent produces output artifacts (response chunks, plan entries, tool results) |
|
|
|
|
In local mode, events flow as JSON-RPC notifications over stdout. In server mode, the A2A SDK manages the HTTP SSE connection. Both modes deliver the same event types with the same payload shapes.
|
|
|
|
**Causal ordering guarantee**: Events within a single task lifecycle are delivered in causal order.
|
|
|
|
### Multi-Turn Interactions
|
|
|
|
A2A natively supports multi-turn interactions through the Task lifecycle. When a server-hosted agent requires client-side input or approval:
|
|
|
|
1. The Task enters the `input-required` state (delivered via `TaskStatusUpdateEvent`)
|
|
2. The client displays the request to the user (permission prompt, file access request, etc.)
|
|
3. The client responds via `message/send` with the task's context ID, providing the requested input
|
|
4. The Task resumes processing
|
|
|
|
This pattern replaces the need for protocol-level callbacks. Platform-specific client-side operations (file access, terminal commands) use `_cleveragents/` extension methods that the client handles locally.
|
|
|
|
### Error Taxonomy
|
|
|
|
A2A uses JSON-RPC 2.0 integer error codes (per the JSON-RPC binding, A2A Section 9.5):
|
|
|
|
| Code | Meaning | Domain Exception(s) |
|
|
|------|---------|---------------------|
|
|
| `-32700` | Parse error | — |
|
|
| `-32600` | Invalid request | — |
|
|
| `-32601` | Method not found | `A2aOperationNotFoundError` |
|
|
| `-32602` | Invalid params | `ValidationError` |
|
|
| `-32603` | Internal error | Any unhandled `Exception` |
|
|
| `-32001` | Entity not found | `ResourceNotFoundError` |
|
|
| `-32002` | Authentication required | `AuthenticationError` |
|
|
| `-32003` | Authorization forbidden | `AuthorizationError` |
|
|
| `-32004` | Invalid state | `BusinessRuleViolation` |
|
|
| `-32005` | Already exists | `DuplicateEntityError` |
|
|
| `-32006` | Budget exceeded | `BudgetExceededError` |
|
|
| `-32007` | Version mismatch | `A2aVersionMismatchError` |
|
|
| `-32008` | Plan error | `PlanError` |
|
|
|
|
### Versioning and Compatibility
|
|
|
|
- The JSON-RPC protocol version is always `"2.0"` in the `jsonrpc` field
|
|
- The A2A protocol version is communicated via the `A2A-Version` HTTP header in server mode
|
|
- CleverAgents extension version is declared in the Agent Card's `extensions` field under `urn:cleveragents:extensions:v1`
|
|
- Servers support the current extension version plus one prior minor version
|
|
- Backward-compatible additions (new optional params, new extension methods) are permitted within a major version; breaking changes require a major version bump
|
|
|
|
### Authentication and Authorization
|
|
|
|
- **Server mode**: Standard HTTP authentication using security schemes declared in the Agent Card (OAuth2, API key, HTTP bearer). The Agent Card's `securitySchemes` field advertises which mechanisms are supported. Authorization is enforced per namespace.
|
|
- **Local mode**: Authentication is bypassed — the agent subprocess runs with the user's local permissions.
|
|
|
|
### Service Facade Mapping
|
|
|
|
Each A2A operation group maps to an Application-layer service. The complete method-to-service routing is documented in the specification's [A2A Integration Architecture](../specification.md#a2a-integration-architecture) and [Server and Client Architecture](../specification.md#server-and-client-architecture) sections.
|
|
|
|
| A2A Category | Service |
|
|
|-------------|---------|
|
|
| Standard message operations | `SessionWorkflow` |
|
|
| Task lifecycle operations | `TaskService` |
|
|
| Plan extension methods | `PlanService`, `PlanLifecycle`, `CorrectionFlow` |
|
|
| Registry extension methods | `ActorService`, `ToolService`, `SkillService`, `ResourceService`, `ProjectService` |
|
|
| Context extension methods | `ContextService` |
|
|
| Sync extension methods | `SyncService` |
|
|
| Namespace extension methods | `NamespaceService` |
|
|
|
|
## Constraints
|
|
|
|
- Clients must not bypass A2A to access storage, repositories, or internal domain services directly.
|
|
- All A2A operations must be implementable over both stdio and HTTP transports with identical semantics.
|
|
- All A2A operations in server mode must require valid authentication (via Agent Card-declared security schemes).
|
|
- A2A responses must use the JSON-RPC 2.0 envelope; ad-hoc response shapes are prohibited.
|
|
- Standard A2A operations must not be modified — use `_cleveragents/` extension methods for platform-specific operations.
|
|
- Streaming events must preserve causal ordering within a single task lifecycle.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- Clients are interchangeable — new clients (e.g., mobile, third-party dashboards) can be built against the A2A standard.
|
|
- Local and server modes share the same protocol surface, eliminating behavioral drift.
|
|
- Alignment with the A2A standard (Linux Foundation, Apache 2.0, multi-language SDKs) enables interoperability with the broader agent ecosystem.
|
|
- Agent Card discovery allows third-party agents and clients to discover CleverAgents capabilities dynamically.
|
|
- The A2A Python SDK provides production-quality transport implementations.
|
|
- JSON-RPC 2.0 is a mature, widely-tooled standard; gRPC and REST bindings are available for future adoption.
|
|
|
|
### Negative
|
|
- The protocol adds upfront design and versioning overhead.
|
|
- Some client-specific optimizations (e.g., batching, caching) are harder when constrained to a shared contract.
|
|
|
|
### Risks
|
|
- Protocol evolution could lag feature development if versioning discipline is not maintained.
|
|
|
|
## Alternatives Considered
|
|
|
|
**Per-client bespoke APIs** — Faster initial development but leads to drift, duplicated logic, and higher long-term maintenance costs. Rejected.
|
|
|
|
**Direct database access for local clients** — Faster reads in local mode but breaks parity with server mode and tightly couples clients to storage schema. Rejected.
|
|
|
|
**Bespoke REST API with custom JSON envelopes** — Functional but isolated from the ecosystem. No interoperability with third-party agents or editors. Ongoing maintenance of custom envelope format. Rejected.
|
|
|
|
**ACP (Agent Client Protocol)** — The predecessor to A2A, also built on JSON-RPC 2.0. Lacked Agent Card discovery, had a smaller ecosystem, and is now deprecated in favor of A2A. A2A retains backward compatibility with ACP's JSON-RPC foundation. Rejected in favor of A2A's broader ecosystem, Linux Foundation governance, and multi-language SDK support.
|
|
|
|
**gRPC** — Strong typing and streaming but adds a code-generation dependency and is less accessible for browser-based clients than JSON-RPC over HTTP. A2A includes a gRPC binding (Section 10) that may be adopted for high-throughput server-to-server communication in the future.
|
|
|
|
## Compliance
|
|
|
|
- **Protocol conformance tests**: Validate all standard A2A operation signatures and response schemas against the A2A specification test suite.
|
|
- **Extension method tests**: Validate all `_cleveragents/` methods against documented parameter and response schemas.
|
|
- **Transport parity tests**: Execute the same A2A test suite over stdio and HTTP transports, asserting identical results.
|
|
- **Authentication tests**: Verify Agent Card-declared security schemes and namespace-scoped authorization in server mode.
|
|
- **Streaming tests**: Ensure event ordering and schema compliance for `TaskStatusUpdateEvent` and `TaskArtifactUpdateEvent` payloads.
|
|
- **Agent Card tests**: Validate the generated Agent Card conforms to the A2A specification schema.
|
|
- **Bypass detection**: Architecture tests verify that no Presentation-layer module imports from the Infrastructure layer directly.
|