d5b122d4a3
CI / lint (push) Successful in 14s
CI / quality (push) Successful in 21s
CI / security (push) Successful in 36s
CI / build (push) Successful in 36s
CI / typecheck (push) Successful in 39s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m57s
CI / integration_tests (push) Successful in 3m23s
CI / docker (push) Successful in 53s
CI / coverage (push) Successful in 5m58s
CI / benchmark-publish (push) Successful in 19m27s
167 lines
9.4 KiB
Markdown
167 lines
9.4 KiB
Markdown
---
|
|
adr_number: 23
|
|
title: Server Mode
|
|
status_history:
|
|
- - '2026-02-16'
|
|
- Proposed
|
|
- Jeffrey Phillips Freeman
|
|
- - '2026-02-16'
|
|
- Accepted
|
|
- Jeffrey Phillips Freeman
|
|
tier: 4
|
|
authors:
|
|
- Jeffrey Phillips Freeman
|
|
superseded_by: null
|
|
related_adrs:
|
|
- number: 1
|
|
title: Layered Architecture
|
|
relationship: Both deployment modes share Domain and Application layers, differing only in Presentation and Infrastructure
|
|
- number: 2
|
|
title: Namespace System
|
|
relationship: Server mode introduces server-prefixed namespaces for multi-server entity resolution
|
|
- number: 5
|
|
title: Technical Stack
|
|
relationship: A2A Python SDK, LangGraph Platform, PostgreSQL, and Helm/Kubernetes are the server mode stack choices
|
|
- number: 19
|
|
title: Storage and Persistence
|
|
relationship: Server mode uses PostgreSQL instead of SQLite for multi-user persistence
|
|
- number: 26
|
|
title: Agent-to-Agent Protocol (A2A)
|
|
relationship: A2A (external standard, JSON-RPC 2.0) is the sole client-server protocol; server mode uses A2A over HTTP, local mode uses A2A over stdio
|
|
- number: 47
|
|
title: A2A Standard Adoption
|
|
relationship: ADR-047 defines the adoption of the external A2A standard that replaces the previous REST-based protocol
|
|
- number: 48
|
|
title: Server Application Architecture
|
|
relationship: ADR-048 defines the concrete server architecture (LangGraph Platform, PostgreSQL, A2A endpoint) that implements server mode
|
|
acceptance:
|
|
votes_for:
|
|
- voter: Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>
|
|
comment: Sharing Domain and Application layers across both modes maximizes code reuse and behavioral consistency
|
|
votes_against: []
|
|
abstentions: []
|
|
---
|
|
## Context
|
|
|
|
CleverAgents starts as a single-user local CLI tool, but the specification envisions a collaborative multi-user deployment where teams share entity definitions, execute plans on shared infrastructure, and collaborate on projects. The system needs a server deployment mode that enables this without requiring a separate codebase — the same domain and application layers must support both local and server modes.
|
|
|
|
## Decision Drivers
|
|
|
|
- The same domain and application logic must run identically in both single-user local and multi-user server deployments
|
|
- Teams need to share entity definitions, execute plans on shared infrastructure, and collaborate without maintaining separate codebases
|
|
- Local mode must work fully offline with zero server dependency
|
|
- Client and server must share namespaces and resolve names identically regardless of deployment mode
|
|
- Infrastructure concerns (database, sandbox, transport) must be swappable without touching domain or application code
|
|
|
|
## Decision
|
|
|
|
CleverAgents supports two deployment modes that share the same Domain and Application layers. **Local mode** is a single-process CLI application with SQLite storage and A2A over stdio. **Server mode** is a multi-user service where the CLI acts as a thin client communicating with a remote server via **A2A over HTTP** (JSON-RPC 2.0). The Infrastructure Layer provides swappable implementations for each mode, enabled by the hexagonal architecture (ADR-001).
|
|
|
|
## Design
|
|
|
|
### Local Mode
|
|
|
|
- Single-process CLI application.
|
|
- All components run in the same Python process.
|
|
- SQLite database for persistence (WAL mode for concurrent reads).
|
|
- All resources are local to the machine.
|
|
- A2A flows over **stdio** — the agent runs as a subprocess, JSON-RPC messages over stdin/stdout.
|
|
- Extension methods (`_cleveragents/*`) resolved in-process by `A2aLocalFacade`.
|
|
- The `local/` namespace is always available.
|
|
- No server dependency — works fully offline.
|
|
|
|
### Server Mode
|
|
|
|
- The CLI operates as a thin client.
|
|
- Communication with the server via **A2A over HTTP** (JSON-RPC 2.0) using `server.url` and `server.token`.
|
|
- The server hosts shared storage (PostgreSQL), namespace resolution, and remote plan execution.
|
|
- Server namespaces (`<username>/`, `<orgname>/`) are available when connected.
|
|
- Entity definitions (actors, actions, skills, tools) can be synced between local and server via `_cleveragents/sync/*` extension methods.
|
|
- Plans can execute on the server, with actor graphs running on LangGraph Platform via RemoteGraph.
|
|
|
|
### Server Infrastructure
|
|
|
|
- **A2A endpoint**: A2A JSON-RPC 2.0 server implemented using the A2A Python SDK's server-side connection handler. This is the sole client-facing interface.
|
|
- **Database**: PostgreSQL via SQLAlchemy (same ORM, different dialect from local SQLite).
|
|
- **Actor execution**: LangGraph Platform via RemoteGraph — each actor graph deploys as a separate RemoteGraph.
|
|
- **Deployment**: Helm chart in `k8s/` directory for Kubernetes deployment.
|
|
- **Authentication**: Token-based authentication via HTTP auth schemes declared in the server's Agent Card.
|
|
|
|
### Sync Mechanism
|
|
|
|
Entity synchronization between client and server uses A2A extension methods (`_cleveragents/sync/*`):
|
|
|
|
- **Auto-sync**: Controlled by `server.sync.auto` (default: `true`). When enabled, entities are synced on startup and after registration changes.
|
|
- **Sync interval**: Background syncs at `server.sync.interval` (default: 300 seconds).
|
|
- **Manual sync**: Can be triggered explicitly when auto-sync is disabled.
|
|
- **Direction**: Server namespaces are downloaded to local cache; local namespace entities are never uploaded automatically.
|
|
|
|
### Namespace Resolution in Server Mode
|
|
|
|
- `local/` always resolves locally, regardless of server connection.
|
|
- `<username>/` and `<orgname>/` resolve against the server.
|
|
- Server-qualified names (`dev:freemo/actor`) resolve against a specific server when multiple servers are connected.
|
|
- The default namespace can be configured to a server namespace via `core.namespace`.
|
|
|
|
### Project Types and Execution Location
|
|
|
|
| Project Type | Definition | Plan Execution |
|
|
|-------------|-----------|---------------|
|
|
| **Local** | Contains at least one local-only resource | Client only |
|
|
| **Remote** | All resources are remotely accessible | Client or Server |
|
|
|
|
Remote projects can have their plans executed on the server, enabling shared infrastructure and centralized execution. When server-hosted agents need to access client-local resources, `_cleveragents/` extension method callbacks (`fs/*`, `terminal/*`) forward the requests to the connected client.
|
|
|
|
### Shared Architecture
|
|
|
|
The key architectural enabler is the hexagonal pattern (ADR-001):
|
|
|
|
- **Domain Layer**: Identical between modes. All business rules, domain models, and domain events are shared.
|
|
- **Application Layer**: Identical between modes. Service facades, workflow engine, and event bus are shared.
|
|
- **Infrastructure Layer**: Swappable implementations per mode:
|
|
- SQLite ↔ PostgreSQL (database)
|
|
- Local file access ↔ A2A callbacks (resource access)
|
|
- Local sandbox ↔ LangGraph Platform RemoteGraph (execution environment)
|
|
- A2aLocalFacade (stdio) ↔ A2A SDK server endpoint (HTTP) (transport)
|
|
|
|
## Constraints
|
|
|
|
- The `local/` namespace must never be synced to a server.
|
|
- Server mode requires `server.url` and `server.token` to be configured.
|
|
- The Domain and Application layers must have zero mode-specific code. All mode differences must be in the Infrastructure Layer.
|
|
- Token authentication is required for all server A2A method calls (enforced via HTTP auth schemes declared in the Agent Card).
|
|
- Local-only projects (containing local-only resources) cannot execute plans on the server.
|
|
- The CLI must function fully offline in local mode, with no server dependency.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- A single codebase supports both local-first development and collaborative server deployment.
|
|
- The hexagonal architecture ensures mode switching is purely an infrastructure concern.
|
|
- Local mode has zero configuration requirements — no server needed.
|
|
- Teams can share entity definitions and execute plans on shared infrastructure without each member maintaining local copies.
|
|
|
|
### Negative
|
|
- Server mode requires operating a server (PostgreSQL, Kubernetes, LangGraph Platform, Helm, authentication).
|
|
- The sync mechanism adds complexity and potential for stale or conflicting entity definitions.
|
|
- Network latency affects all operations in server mode.
|
|
|
|
### Risks
|
|
- Sync conflicts between local modifications and server-side changes could produce inconsistent entity states.
|
|
- Server downtime renders server-namespaced entities unavailable.
|
|
- Security of the authentication token and HTTPS transport must be ensured.
|
|
|
|
## Alternatives Considered
|
|
|
|
**Separate server codebase** — Would require maintaining two implementations of the same domain logic, leading to divergence and doubled maintenance. The shared-layer approach avoids this.
|
|
|
|
**Peer-to-peer sync (no central server)** — More resilient but significantly more complex for conflict resolution, namespace management, and access control. A central server provides simpler semantics for organizational namespaces and shared execution.
|
|
|
|
## Compliance
|
|
|
|
- **Mode isolation tests**: Tests verify that Domain and Application layer code has no mode-specific imports or branching.
|
|
- **Infrastructure swappability tests**: Tests verify that swapping SQLite for PostgreSQL, local sandbox for RemoteGraph, etc., produces correct behavior.
|
|
- **Offline functionality tests**: Tests verify that local mode works completely without network access.
|
|
- **Sync tests**: Integration tests verify entity sync behavior including auto-sync, manual sync, and conflict handling via `_cleveragents/sync/*` methods.
|
|
- **Authentication tests**: Tests verify that the A2A authentication flow works correctly and that unauthenticated requests are rejected.
|