---
adr_number: 48
title: "Server Application Architecture"
status_history:
  - ["2026-03-11", "Draft", "Jeffrey Phillips Freeman"]
  - ["2026-03-11", "Proposed", "Jeffrey Phillips Freeman"]
  - ["2026-03-11", "Accepted", "Jeffrey Phillips Freeman"]
tier: 4
authors: ["Jeffrey Phillips Freeman"]
superseded_by:
related_adrs:
  - number: 1
    title: "Layered Architecture"
    relationship: "The server shares the same Domain and Application layers as the client; only Infrastructure and Presentation layers differ"
  - number: 22
    title: "LangChain/LangGraph Integration"
    relationship: "The server deploys actor StateGraphs to LangGraph Platform and invokes them via RemoteGraph"
  - number: 23
    title: "Server Mode"
    relationship: "Refines ADR-023's server mode design with concrete architecture — LangGraph Platform for execution, A2A standard for protocol, PostgreSQL for persistence"
  - number: 26
    title: "Agent-to-Agent Protocol (A2A)"
    relationship: "The server implements the A2A standard endpoint; ADR-026 defines the protocol boundary role"
  - number: 47
    title: "A2A Standard Adoption"
    relationship: "ADR-047 defines the protocol the server speaks (A2A standard + extensions); this ADR defines the server that implements it"
acceptance:
  votes_for:
    - voter: "Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>"
      comment: "A separate server application sharing domain/application layers with the client, backed by LangGraph Platform for remote execution, provides clean separation of concerns while maximizing code reuse"
  votes_against: []
  abstentions: []
---
## Context

ADR-023 established that CleverAgents supports local and server deployment modes sharing Domain and Application layers, differing only in Infrastructure and Presentation. ADR-047 adopted the A2A standard as the sole client-server protocol. What remains unspecified is the concrete architecture of the server application itself — how it is structured, how it executes actor graphs remotely, how it manages multi-user state, and how it integrates with the shared layers.

## Decision Drivers

- The server must share the same Domain and Application layers as the client to avoid behavioral drift (ADR-001, ADR-023)
- Remote actor graph execution must not limit plan capabilities — different actors for different plan phases (strategy, execution) must each deploy independently
- The server must speak the A2A standard protocol (ADR-047) as its sole client-facing interface
- Multi-user persistence requires PostgreSQL (not SQLite) with proper isolation and namespace-scoped authorization
- The server must be deployable to Kubernetes via Helm charts for production environments
- LangGraph Platform is the established graph execution engine (ADR-022) and provides RemoteGraph for remote invocation

## Decision

The CleverAgents server is a **separate application** (distinct repository/deployment unit) that shares the same Domain and Application layers as the client. It implements the A2A standard endpoint (JSON-RPC 2.0 over HTTP) for all client communication, delegates actor graph execution to **LangGraph Platform** via **RemoteGraph**, and uses PostgreSQL for multi-user persistence.

## Design

### Server Application Structure

The server is organized following the same four-layer architecture as the client (ADR-001), sharing two layers and providing its own implementations for the other two:

| Layer | Client | Server | Shared? |
|-------|--------|--------|---------|
| **Domain** | Business rules, domain models, domain events | Same | Yes — identical package |
| **Application** | Service facades, workflows, event bus | Same | Yes — identical package |
| **Infrastructure** | SQLite, local sandbox, local file access, `A2aLocalFacade` | PostgreSQL, LangGraph Platform RemoteGraph, server-side sandbox, A2A SDK server | No — different implementations |
| **Presentation** | CLI (Typer), TUI (Textual), IDE plugin | A2A JSON-RPC 2.0 endpoint | No — different entry points |

The shared Domain and Application layers are consumed as a Python package dependency. This ensures zero behavioral drift between local and server modes.

### Presentation Layer: A2A Endpoint

The server's Presentation layer is an **A2A JSON-RPC 2.0 endpoint** implemented using the A2A Python SDK's server-side connection handler. This is the **only** client-facing interface — there is no REST API, no GraphQL, no separate admin endpoint.

The endpoint handles:

- **Standard A2A methods**: `message/send`, `message/stream` — routed to `SessionWorkflow` and actor execution via Tasks
- **Extension methods**: `_cleveragents/*` — routed to Application-layer services (PlanService, RegistryServices, SyncService, etc.)
- **Multi-turn interaction**: Tasks entering `input-required` state prompt the connected client for decisions or permissions

### Infrastructure Layer: LangGraph Platform

Actor graphs (StateGraphs defined in YAML) are **deployed to LangGraph Platform** as separate deployments. The server invokes them via **RemoteGraph**:

```
Client ──A2A──→ Server A2A Endpoint
                   │
                   ├── SessionWorkflow (Application Layer)
                   │     │
                   │     └── RemoteGraph.invoke(actor_graph, state)
                   │           │
                   │           └── LangGraph Platform (remote actor execution)
                   │                 ├── Strategy Actor Graph
                   │                 ├── Execution Actor Graph
                   │                 └── Estimation Actor Graph
                   │
                   └── Extension Method Handlers
                         ├── PlanService
                         ├── RegistryServices
                         ├── SyncService
                         └── NamespaceService
```

This does **not** limit plan execution. Different actors for different plan phases (strategy vs. execution vs. estimation) each deploy as **separate RemoteGraphs**. The `SessionWorkflow` orchestrates them the same way it orchestrates local actor graphs, but through the RemoteGraph interface instead of direct in-process invocation.

### Infrastructure Layer: Persistence

| Component | Technology | Notes |
|-----------|-----------|-------|
| Database | PostgreSQL via SQLAlchemy | Same ORM as client (SQLite), different dialect |
| Migrations | Alembic | Schema migrations for server-specific tables (users, tokens, namespace ACLs) |
| Session store | PostgreSQL | Multi-user session persistence with namespace isolation |
| Plan store | PostgreSQL | Plan lifecycle records, decision trees, artifacts |

The SQLAlchemy repository implementations are shared between client and server where the schema is identical. Server-specific tables (authentication, namespace ACLs, user management) are additive.

### Infrastructure Layer: Additional Components

| Component | Technology | Purpose |
|-----------|-----------|---------|
| Logging | structlog | Structured logging consistent with client (ADR-025) |
| Caching | Redis (optional) | Multi-instance session affinity, rate limiting. Single-instance deployments can use in-memory caching. |
| Task queue | None (synchronous) | Plans execute synchronously via RemoteGraph. No background job queue — the A2A connection stays open during execution with streaming notifications. |

### Security Architecture

**Authentication flow:**

1. Client discovers the server's Agent Card (via `/.well-known/agent.json`) which declares supported auth schemes and `_cleveragents` extensions
2. Client authenticates using the declared HTTP auth scheme (e.g., Bearer token via `Authorization: Bearer <server.token>`)
3. Server validates the token against its user/token store
4. All subsequent requests include the auth credentials; the `A2A-Version` header identifies the protocol version

**Authorization:**

- Namespace-scoped: users can only access entities in namespaces they have been granted access to
- The `local/` namespace is never accessible via server — it exists only on the client
- Server namespaces (`<username>/`, `<orgname>/`) have explicit ACLs

**Transport security:**

- HTTPS required for all production deployments (TLS termination at ingress)
- The A2A SDK HTTP transport supports standard TLS

### Deployment Architecture

| Component | Technology | Notes |
|-----------|-----------|-------|
| Container | Docker | Server packaged as container image |
| Orchestration | Kubernetes | Production deployment target |
| Configuration | Helm chart (`k8s/`) | Configurable replicas, resource limits, ingress |
| Ingress | Kubernetes Ingress | TLS termination, routing |
| Database | PostgreSQL (managed or self-hosted) | External to the application container |
| LangGraph Platform | Managed or self-hosted | External service for graph execution |

### Sync Protocol

Entity synchronization between client and server uses A2A extension methods:

| Method | Purpose |
|--------|---------|
| `_cleveragents/sync/pull` | Download server namespace entities to local cache |
| `_cleveragents/sync/push` | Upload local entity definitions to a server namespace |
| `_cleveragents/sync/status` | Compare local and server entity versions |

Sync behavior:

- **Auto-sync** (`server.sync.auto`): Entities sync on connection and at `server.sync.interval` (default: 300s)
- **Direction**: Server → local for server namespaces; local → server only on explicit push
- **Conflict resolution**: Server version wins by default; conflicts are surfaced to the user via `sync/status`
- The `local/` namespace is **never** synced

### Technology Stack

| Component | Version | Purpose |
|-----------|---------|---------|
| Python | >= 3.13 | Runtime |
| A2A Python SDK (`a2a-sdk`) | Latest | A2A JSON-RPC 2.0 server implementation |
| LangGraph Platform | Latest | Remote actor graph execution |
| PostgreSQL | >= 15 | Multi-user persistence |
| SQLAlchemy | >= 2.0 | ORM (shared with client) |
| Alembic | >= 1.13 | Database migrations |
| structlog | >= 24.1 | Structured logging |
| Redis | >= 7.0 (optional) | Caching, session affinity for multi-instance |
| Helm | >= 3.0 | Kubernetes deployment |

## Constraints

- The server **must not** contain any Domain or Application layer code that is not shared with the client. All mode differences must be in Infrastructure and Presentation layers.
- The server's **only** client-facing interface is the A2A JSON-RPC 2.0 endpoint. No REST API, no GraphQL, no admin endpoints.
- Actor graph execution **must** go through LangGraph Platform RemoteGraph — the server does not execute actor graphs in-process.
- The `local/` namespace must never be accessible or syncable via the server.
- All A2A connections require authentication (via HTTP auth schemes declared in the Agent Card) before any task operations.

## Consequences

### Positive

- Maximum code reuse — Domain and Application layers are identical, eliminating behavioral drift between local and server modes
- LangGraph Platform provides production-grade graph execution with built-in scaling, persistence, and monitoring
- The A2A-only interface ensures all clients (CLI, TUI, IDE, third-party) interact identically with the server
- RemoteGraph per actor enables independent scaling of different actor types (strategy actors may need different resources than execution actors)
- PostgreSQL provides proven multi-user persistence with proper transaction isolation

### Negative

- Dependency on LangGraph Platform — the server cannot execute actors without it
- Operating a server requires PostgreSQL, Kubernetes, and optionally Redis — significantly more infrastructure than local mode
- The A2A Python SDK is relatively new; production edge cases may require SDK contributions or workarounds

### Risks

- LangGraph Platform availability directly affects server plan execution. Mitigation: health checks and graceful degradation (report unavailability, don't silently fail)
- Network latency between server and LangGraph Platform adds overhead to every actor invocation. Mitigation: co-locate server and LangGraph Platform in the same region/cluster
- The shared Domain/Application package must be versioned carefully to avoid incompatibilities between client and server releases. Mitigation: semantic versioning with backward compatibility guarantees

## Alternatives Considered

**Single monolithic server (no LangGraph Platform)** — Execute actor graphs in the server process directly. Simpler deployment but loses LangGraph Platform's scaling, persistence, and monitoring. Doesn't align with ADR-022's adoption of LangGraph. Rejected.

**Server in the same repository as the client** — Simpler development workflow but conflates deployment units and makes it harder to version the shared layers independently. A separate application with shared package dependencies is cleaner. Rejected.

**Multiple API surfaces (A2A + REST admin)** — An admin REST API alongside A2A for server management. Adds a second protocol surface, complicates authentication, and violates the single-protocol principle. Admin operations are handled via `_cleveragents/` extension methods. Rejected.

## Compliance

- **Shared layer tests**: Tests verify that Domain and Application layers imported by the server are byte-identical to those used by the client (same package version).
- **A2A conformance tests**: The server passes the A2A standard test suite for all standard methods.
- **Extension method tests**: All `_cleveragents/` methods are tested against documented parameter and response schemas.
- **RemoteGraph integration tests**: Tests verify actor graph deployment to and invocation via LangGraph Platform.
- **Authentication tests**: Tests verify the `authenticate` flow and namespace-scoped authorization.
- **Sync tests**: Integration tests verify pull/push/status sync operations including conflict detection.
- **Deployment tests**: Helm chart renders correctly and the container starts with valid configuration.
