# Architecture — Detailed Reference

## Four-Layer Architecture

CleverAgents follows Domain-Driven Design with strict dependency rules: outer layers depend on inner layers, never the reverse. Architecture tests (import-linter) enforce this on every commit.

```
Presentation → Application → Domain → Infrastructure
     ↓               ↓           ↓           ↓
  CLI/TUI      Services      Models      DB/LLM/Files
```

### Presentation Layer
- **CLI** (Typer + Rich): `agents <noun> <verb>` command pattern
- **TUI** (Textual): reactive terminal UI; same A2A operations as CLI
- **Web** (Textual Web): TUI served as web app
- **IDE Plugin** (embedded TUI): communicates via A2A; works in local or server mode
- **A2A Server Endpoint**: JSON-RPC 2.0 server for server-mode clients

### Application Layer
- **Service Facade**: PlanService, ProjectService, ActorService, ContextService, ToolService, SkillService, ResourceService
- **Workflow Engine**: PlanLifecycle, SessionWorkflow, CorrectionFlow, MergeWorkflow
- **Event Bus**: EventEmitter, StructuredLog, MetricsCollector
- **DI Container**: dependency-injector DeclarativeContainer (single composition root)

### Domain Layer
- **Domain Models**: Plan, Decision, Project, Resource, Actor, Action, Tool, Skill, Session, Invariant, AutomationProfile, Checkpoint, CorrectionAttempt
- **Domain Services**: InvariantEnforcer, AutonomyController, ContextBuilder, MergeResolver
- **Repository Interfaces**: Protocol classes (no DI framework annotations)
- **Domain Events**: PlanCreated, PhaseChanged, DecisionMade, ToolInvoked, ApplyCompleted, CorrectionRequested

### Infrastructure Layer
- **Database**: SQLite (local) / PostgreSQL (server) via SQLAlchemy + Alembic
- **Indexing**: Tantivy (full-text), FAISS/Qdrant (vector), Neo4j/rdflib (graph)
- **Sandbox**: GitWorktree, FsCopy (copy-on-write), TxnRollback, NoOp
- **LLM/AI Runtime**: LangChain, LangGraph, RxPY (reactive streams), MCP SDK
- **External**: MCP Servers, Agent Skills folders, REST/gRPC clients
- **LSP Runtime**: LSP server manager, LSPToolAdapter, language servers
- **File System**: Watchdog (file watching), Git CLI, OS subprocess

---

## Deployment Modes

| | Local Mode | Server Mode |
|--|-----------|-------------|
| Process | Single Python process | Multi-user service; CLI is thin client |
| A2A transport | stdio (agent as subprocess) | HTTP to CleverAgents server |
| Database | SQLite | PostgreSQL |
| Actor execution | In-process | LangGraph Platform (RemoteGraph) |
| Configuration | `~/.local/share/cleveragents/` | Configured via server.url + server.token |

---

## A2A Protocol (Full Detail)

### Why A2A Exists

A2A is the **fundamental boundary between Presentation and Application layers**. It ensures:
- All clients (CLI, TUI, IDE, third-party) are interchangeable
- Local mode and server mode produce identical behavior
- Third-party client development is practical
- A single test suite validates both transports

### Transport Modes

**Local mode (stdio):**
```
CLI → A2A over stdio → Agent Subprocess → A2aLocalFacade → ServiceFacade.method()
```

**Server mode (HTTP):**
```
CLI → A2A over HTTP → CleverAgents A2A Server → ServiceFacade.method()
                                                      ↓
                                           RemoteGraph → LangGraph Platform
```

**External agent mode (split routing):**
```
Standard A2A operations → External A2A-compliant agent server
_cleveragents/* methods → CleverAgents server
```

### Complete Method Routing

**Standard A2A Operations:**

| Operation | Service Method |
|-----------|----------------|
| `message/send` | `SessionWorkflow.tell()` |
| `message/stream` | `SessionWorkflow.tell()` (streaming) |
| `session/new` | `SessionWorkflow.create()` |
| `session/load` | `SessionWorkflow.resume()` |
| `session/cancel` | `PlanService.cancel()` |

**Plan Extension Methods:**

| Extension Method | Service Method |
|-----------------|----------------|
| `_cleveragents/plan/use` | `PlanService.create_plan()` |
| `_cleveragents/plan/execute` | `PlanLifecycle.execute()` |
| `_cleveragents/plan/apply` | `PlanLifecycle.apply()` |
| `_cleveragents/plan/cancel` | `PlanService.cancel()` |
| `_cleveragents/plan/status` | `PlanService.get_status()` |
| `_cleveragents/plan/tree` | `PlanService.get_tree()` |
| `_cleveragents/plan/explain` | `PlanService.explain_decision()` |
| `_cleveragents/plan/correct` | `CorrectionFlow.correct()` |
| `_cleveragents/plan/diff` | `PlanService.get_diff()` |
| `_cleveragents/plan/artifacts` | `PlanService.get_artifacts()` |
| `_cleveragents/plan/prompt` | `PlanService.inject_guidance()` |
| `_cleveragents/plan/rollback` | `PlanLifecycle.rollback()` |

**Registry Extension Methods (pattern for all entity types):**

| Pattern | Service Pattern |
|---------|----------------|
| `_cleveragents/registry/{entity}/list` | `{Entity}Service.list()` |
| `_cleveragents/registry/{entity}/show` | `{Entity}Service.show()` |
| `_cleveragents/registry/{entity}/add` | `{Entity}Service.add()` |
| `_cleveragents/registry/{entity}/update` | `{Entity}Service.update()` |
| `_cleveragents/registry/{entity}/remove` | `{Entity}Service.remove()` |

Where `{entity}` ∈ {actor, skill, tool, validation, resource, resource_type, project, action, automation_profile, invariant, lsp}

### Streaming Events (SSE via message/stream)

| Event | When Emitted | Payload |
|-------|-------------|---------|
| `TaskStatusUpdateEvent` | Agent tokens, task state changes, profile switches | status: state + message with Parts |
| `TaskArtifactUpdateEvent` | Tool results, plan artifacts | artifact: named artifact with Parts |

**Causal ordering guarantee**: Events arrive in causal order within a session/plan lifecycle.

### Authentication

- **Local mode**: Bypassed (runs with local user permissions)
- **Server mode**: Agent Card discovery → HTTP auth (Bearer token) → all requests authenticated
- **Authorization**: Namespace-scoped; `local/` namespace never accessible via server

### Error Codes

| Code | Meaning | Exception |
|------|---------|-----------|
| -32700 | Parse error (malformed JSON) | — |
| -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` |

---

## Dependency Injection

The DI container (dependency-injector DeclarativeContainer) is the single composition root.

**Provider types:**
- `Singleton`: DB engine, repositories, event bus, index backends
- `Factory`: sandbox instances, execution contexts, per-request objects
- `Configuration`: TOML config + environment variables

**Wiring rules:**
1. Domain Layer defines Repository interfaces as `Protocol` classes
2. Infrastructure Layer provides concrete implementations
3. DI container maps protocols to implementations
4. Application Layer services receive dependencies via constructor injection
5. Domain code NEVER imports `dependency-injector`

**Container rules:**
1. All cross-layer dependencies flow through DI container
2. Container initialized exactly once at startup
3. Domain code never imports or references the DI library
4. All services registered in container before use
5. Startup self-test verifies all providers resolve

---

## Technical Stack

### Core Runtime
| Tech | Version | Role |
|------|---------|------|
| Python | >= 3.13 | Primary language |
| Hatchling | >= 1.21.0 | PEP 517 build backend |
| uv | >= 0.8.0 | Package installer (10-100x faster than pip) |

### CLI and Presentation
| Tech | Role |
|------|------|
| Typer | CLI framework (Click + Rich + type hints) |
| Rich | Terminal rendering (panels, tables, trees, spinners) |
| Textual | TUI framework (reactive; also Textual Web for browser) |

### LLM and AI Runtime
| Tech | Version | Role |
|------|---------|------|
| LangChain | >= 0.2.14 | LLM abstraction, tool calling, prompt templates |
| LangGraph | (transitive) | Stateful workflow orchestration, MemorySaver, streaming |
| LangChain provider packages | varies | langchain-openai, langchain-anthropic, langchain-google-genai, etc. |
| LangChain Community | >= 0.2.14 | FAISS vector store, FakeListLLM (testing) |
| RxPY | >= 3.2.0 | Reactive streams, event routing, backpressure |
| MCP SDK | >= 1.4.0 | Model Context Protocol client |

### Data and Persistence
| Tech | Version | Role |
|------|---------|------|
| SQLite | (system) | Local mode database (WAL mode for concurrent reads) |
| PostgreSQL | — | Server mode database |
| SQLAlchemy | (transitive) | ORM, session management, Unit of Work |
| Alembic | >= 1.13.1 | Database schema migrations |
| python-ulid | >= 2.7.0 | ULID generation (lexicographically sortable) |

### Indexing and Code Intelligence
| Tech | Role |
|------|------|
| Tantivy (tantivy-py) | Full-text search (Rust-based, sub-millisecond) |
| FAISS (faiss-cpu) | Vector similarity search (semantic code search) |
| Qdrant | External vector DB (production, horizontal scaling) |
| Neo4j | Knowledge graph (call graphs, class hierarchies) |
| rdflib >= 7.1.4 | In-process RDF graph store |
| OpenAI Embeddings | Default embedding provider (text-embedding-3-small) |

### Configuration and Validation
| Tech | Version | Role |
|------|---------|------|
| Pydantic | >= 2.7.0 | All domain models, config, API schemas |
| Pydantic Settings | >= 2.11.0 | Env vars (CLEVERAGENTS_ prefix), .env files |
| Jinja2 | >= 3.1.0 | Actor system prompts, YAML interpolation |
| TOML (stdlib tomllib) | — | Global configuration file format |
| YAML (PyYAML) | — | Entity definition format |

### Testing
| Tech | Version | Role |
|------|---------|------|
| Behave | >= 1.2.6 | BDD feature tests (primary unit test framework) |
| Robot Framework | >= 7.3.2 | Integration tests (keyword-driven, CLI workflows) |
| pytest | >= 8.0.0 | Unit tests |
| pytest-asyncio | >= 0.23.0 | Async test support |
| Hypothesis | >= 6.136.6 | Property-based testing |
| ASV | >= 0.6.5 | Performance benchmarks |

### Code Quality
| Tech | Version | Role |
|------|---------|------|
| Ruff | >= 0.1.0 | Linting and formatting |
| Pyright | >= 1.1.350 | Strict type checking |

### Infrastructure
| Tech | Role |
|------|------|
| Docker (multi-stage) | python:3.13-slim, non-root appuser (uid 1000) |
| Helm | Kubernetes deployment (k8s/ directory) |
| Nox | >= 2025.4.22 — task automation |
| Forgejo CI | Self-hosted; GitHub Actions-compatible workflow syntax |

### Observability
| Tech | Role |
|------|------|
| structlog >= 24.4.0 | Structured JSON logging with context binding |
| LangSmith (optional) | LLM observability (tracing, token usage, cost) |

### Additional Libraries
| Tech | Role |
|------|------|
| dependency-injector >= 4.41.0 | DI container (DeclarativeContainer) |
| watchdog >= 4.0.0 | Filesystem monitoring for auto-reindex |
| numpy >= 2.1.0 | Vector operations for embedding similarity |
| uvicorn >= 0.30.1 | ASGI server for server-mode A2A endpoint |
