--- 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 " 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 `) 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 (`/`, `/`) 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.