Files
cleveragents-core/docs/adr/ADR-026-agent-client-protocol.md

12 KiB

ADR-026: Agent Client Protocol (ACP)

Status: Accepted
Date: 2026-02-17
Supersedes: None
Author(s): Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com
Approver(s): Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com

Context

CleverAgents is accessed through multiple presentation-layer clients — CLI, TUI, Web, and an IDE plugin — and can operate in both local (single-process) and server (multi-user HTTPS) 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

CleverAgents adopts the Agent Client Protocol (ACP) as the versioned contract governing all client-to-backend communication. ACP defines canonical operations for sessions, plans, registries, context, and event streaming. In local mode ACP maps to in-process service facade calls; in server mode it is implemented by the REST API over HTTPS.

Design

Architectural Role

ACP 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, Web, IDE plugin, REST API) to the Application-layer Service Facade represents an ACP operation. No Presentation-layer module is permitted to bypass ACP and access Domain or Infrastructure services directly.

This boundary role makes ACP 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 ACP is the protocol surface through which every client operation flows.

Protocol Scope

ACP covers five operation groups:

Group Operations Service(s)
Session lifecycle create, resume, list, show, delete, export, import, tell SessionWorkflow
Plan lifecycle use, execute, apply, cancel, status, tree, explain, correct, diff, artifacts, prompt, rollback PlanService, PlanLifecycle, CorrectionFlow
Registries list / show / add / update / remove for actors, skills, tools, validations, resources, resource types, projects, actions, automation profiles, invariants ActorService, ToolService, SkillService, ResourceService, ProjectService
Context operations context show, context inspect, context simulate, context set ContextService
Event streaming plan state changes, tool execution events, validation results, structured log events EventEmitter (via SSE or in-process subscription)

Every CLI command maps 1:1 to an ACP operation. When a user runs agents plan status <ID>, the CLI constructs an ACP plan.status request, sends it through the active transport, and renders the response.

Request / Response Envelope

Every ACP operation uses a canonical JSON envelope:

Request:

{
  "acp_version": "1.0",
  "request_id": "<ULID>",
  "operation": "plan.status",
  "params": { "plan_id": "01HXRCF1..." },
  "auth": { "token": "..." }
}

Successful response:

{
  "acp_version": "1.0",
  "request_id": "<ULID>",
  "status": "ok",
  "data": { "plan_id": "01HXRCF1...", "phase": "execute", "state": "running" },
  "error": null,
  "timing": { "duration_ms": 42 }
}

Error response:

{
  "acp_version": "1.0",
  "request_id": "<ULID>",
  "status": "error",
  "data": null,
  "error": { "code": "PLAN_NOT_FOUND", "message": "No plan with ID 01HXRCF1...", "details": {} }
}

Error objects carry code (machine-readable), message (human-readable), and optional details (structured context).

Transport Duality

ACP is transport-agnostic at the specification level. The system ships with two transport implementations:

Local Mode — In-Process Calls

CLI  ──→  ACPLocalTransport  ──→  ServiceFacade.method()  ──→  Domain / Infrastructure

The ACPLocalTransport translates ACP operation names to direct Python method calls on the Service Facade. No serialization, no network, no authentication. The adapter enforces the ACP contract boundary — clients cannot call internal services directly.

Server Mode — HTTPS + JSON

CLI  ──→  ACPHTTPTransport  ──→  HTTPS POST  ──→  FastAPI Router  ──→  ServiceFacade.method()

The ACPHTTPTransport serializes each operation into the canonical JSON request envelope, sends it to the REST API, and deserializes the JSON response envelope. The FastAPI router maps URL paths to Service Facade methods using the same operation-to-service mapping.

Architectural enforcement of the duality:

  • The same ACP test suite runs in both modes (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.

Event Streaming

ACP provides real-time event channels for long-running operations:

  • Server mode: Server-Sent Events (SSE) over a persistent HTTPS connection at /api/v1/events/stream. Clients filter by plan_id and/or event_type.
  • Local mode: In-process subscription via RxPY observables or callback registration.

Event types:

Event Type Emitted When
plan.created Plan instantiated from action
plan.phase_changed Phase transition (Strategize, Execute, Apply)
plan.state_changed State change within a phase
plan.decision_made Decision recorded in decision tree
tool.invoked / tool.completed Tool execution start/finish
validation.completed Validation finishes (pass/fail)
plan.apply_completed Apply phase finishes
plan.error Unrecoverable error
session.message Orchestrator produces a message

Causal ordering guarantee: Events within a single plan lifecycle are delivered in causal order. A plan.phase_changed for Execute always arrives after the corresponding Strategize completion event.

Error Taxonomy

ACP defines structured error codes for programmatic handling:

Error Code HTTP Status Meaning
AUTH_REQUIRED 401 Missing or expired token
AUTH_FORBIDDEN 403 Insufficient namespace access
NOT_FOUND 404 Entity does not exist
ALREADY_EXISTS 409 Duplicate entity
INVALID_PARAMS 422 Parameter validation failure
INVALID_STATE 409 Operation not valid in current state
BUDGET_EXCEEDED 429 Cost budget exceeded
VERSION_MISMATCH 400 Unsupported ACP version
INTERNAL_ERROR 500 Unexpected server failure

Versioning and Compatibility

  • Each client advertises acp_version during connection.
  • Servers must support the current minor version plus one prior minor version.
  • Backward-compatible additions (new optional fields, new operations) are permitted within a major version; breaking changes require a major version bump.
  • Multiple major versions may be served simultaneously via URL path versioning (/api/v1/, /api/v2/).

Authentication and Authorization

  • Server mode: Token-based authentication (server.token) required for all ACP requests. The token maps to the Authorization: Bearer <token> header in HTTPS. Authorization is enforced per namespace.
  • Local mode: Authentication is bypassed but the ACP operation surface remains identical.

Service Facade Mapping

Each ACP operation group maps to an Application-layer service. The complete operation-to-endpoint-to-service routing is documented in the specification's ACP Integration Architecture section.

ACP Group Service
Session SessionWorkflow
Plan PlanService, PlanLifecycle, CorrectionFlow
Registries ActorService, ToolService, SkillService, ResourceService, ProjectService
Context ContextService
Events EventEmitter (via SSE or in-process subscription)

Constraints

  • Clients must not bypass ACP to access storage, repositories, or internal domain services directly.
  • All ACP operations must be implementable in both local and server modes with identical semantics.
  • All ACP operations in server mode must require valid authentication.
  • ACP responses must use the canonical JSON envelope; ad-hoc response shapes are prohibited.
  • Event streaming must preserve causal ordering within a single plan lifecycle.

Consequences

Positive

  • Clients are interchangeable — new clients (e.g., mobile, third-party dashboards) can be built against the same stable contract.
  • Local and server modes share the same operational surface, eliminating behavioral drift.
  • Versioning guarantees backward compatibility for at least one prior minor version.

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.
  • SSE streaming channels may become a bottleneck for plans with very high event throughput.

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.

gRPC — Strong typing and streaming but adds a code-generation dependency and is less accessible for browser-based clients than JSON over HTTPS. May be revisited for high-throughput server-to-server communication.

Compliance

  • Contract tests: Validate all ACP endpoints against the canonical schema for every supported version.
  • Local/server parity tests: Execute the same ACP test suite in both deployment modes and assert identical results.
  • Authentication tests: Verify token enforcement and namespace authorization in server mode.
  • Streaming tests: Ensure event ordering and schema compliance for SSE event payloads.
  • Bypass detection: Architecture tests verify that no Presentation-layer module imports from the Infrastructure layer directly.
ADR Title Relationship
ADR-001 Layered Architecture ACP defines the fundamental boundary between the Presentation and Application layers in the four-layer architecture
ADR-006 Plan Lifecycle ACP's plan operation group exposes the full plan lifecycle (use, execute, apply, cancel, correct, rollback) to all clients
ADR-020 Session Model ACP defines the session lifecycle operations (create, tell, export, import) exposed to clients
ADR-021 CLI and Output Rendering Every CLI command maps 1:1 to an ACP operation; the CLI is a thin rendering layer over ACP
ADR-023 Server Mode ACP is the client-server contract implemented by the REST API in server mode; the transport duality (local facade vs HTTPS) is the mechanism that keeps both modes behaviorally identical
ADR-025 Observability and Logging ACP event streaming delivers structured log events and plan state changes to subscribed clients
ADR-027 Language Server Protocol (LSP) Integration LSP servers are Infrastructure-layer components attached to actors; the IDE plugin (Presentation layer) communicates through ACP independently of LSP

Acceptance

Votes For

Voter Comment
Jeffrey Phillips Freeman Jeffrey.Freeman@CleverThis.com ACP provides the standardized agent-to-agent communication layer needed for multi-actor orchestration

Total: 1

Votes Against

Voter Comment

Total: 0

Abstentions

Voter Comment

Total: 0