# ADR-049: CLI Communication Pattern

**Status**: Accepted
**Date**: 2026-04-16
**Issues**: #9899, #9859

## Context

The CleverAgents CLI is the primary user-facing interface for the platform. It is implemented in the Presentation layer and communicates with the Application layer to execute commands.

### Current State: Direct Import Pattern

The current CLI implementation uses **direct Python imports** to call Application-layer services:

```python
# Current pattern (Presentation layer)
from cleveragents.application.plan_service import PlanService
from cleveragents.application.project_service import ProjectService

def plan_execute(plan_id: str):
    service = PlanService()
    service.execute(plan_id)
```

This creates a **reverse dependency**: the Presentation layer directly imports from the Application layer, bypassing the A2A protocol boundary defined in ADR-001 (Layered Architecture) and ADR-047 (A2A Standard Adoption).

### The A2A Specification

ADR-047 establishes that **all client-server interaction must flow through A2A**. The A2A protocol is the sole communication contract between the Presentation and Application layers. In server mode, this is already enforced -- CLI commands route through A2A over HTTP. In local mode, the intent is for CLI commands to route through A2A over stdio (via `A2aLocalFacade`).

### The Problem

The direct import pattern creates several issues:

1. **Architectural violation**: The Presentation layer has a compile-time dependency on the Application layer, violating the layered boundary defined in ADR-001.
2. **Import-linter failures**: The `import-linter` tool flags these imports as boundary violations in CI.
3. **Reverse dependency**: If the Application layer changes its internal API, the CLI breaks -- even if the A2A contract is unchanged.
4. **Testing complexity**: CLI tests must mock Application-layer internals rather than the A2A protocol boundary.
5. **Inconsistency**: Server-mode CLI correctly uses A2A; local-mode CLI bypasses it.

## Decision

### Immediate: Local CLI Exemption

The direct import pattern is **permitted under a documented local CLI exemption** until M9 (v3.8.0). This exemption is granted because:

- The full A2A migration requires significant refactoring across all CLI command handlers.
- The local-mode A2A transport (`A2aLocalFacade` over stdio) is not yet fully implemented.
- The performance impact of routing all local CLI commands through A2A needs measurement.

**Exemption Rules**:

1. The exemption applies **only** to the local (non-server) CLI execution path.
2. All server-mode CLI commands **must** route through A2A (already enforced; no exemption granted).
3. The `import-linter` configuration is updated to explicitly allow the exempted imports with a `# cli-exemption: local-only` annotation in the import-linter config file.
4. **No new direct imports** may be added without a corresponding issue tracking the M9 migration.
5. All exempted imports must be documented in `docs/adr/ADR-049-cli-communication-pattern.md` (this document).

**Import-Linter Configuration**:

```ini
[importlinter:contract:cli-to-application]
name = CLI must not import Application layer directly
type = forbidden
source_modules = cleveragents.cli
forbidden_modules = cleveragents.application
ignore_imports =
    # cli-exemption: local-only -- tracked for M9 migration
    cleveragents.cli.commands.plan:cleveragents.application.plan_service
    cleveragents.cli.commands.project:cleveragents.application.project_service
    cleveragents.cli.commands.actor:cleveragents.application.actor_service
    cleveragents.cli.commands.resource:cleveragents.application.resource_service
    cleveragents.cli.commands.action:cleveragents.application.action_service
    cleveragents.cli.commands.invariant:cleveragents.application.invariant_service
    cleveragents.cli.commands.session:cleveragents.application.session_service
    cleveragents.cli.commands.config:cleveragents.application.config_service
    cleveragents.cli.commands.skill:cleveragents.application.skill_service
    cleveragents.cli.commands.tool:cleveragents.application.tool_service
    cleveragents.cli.commands.validation:cleveragents.application.validation_service
    cleveragents.cli.commands.automation_profile:cleveragents.application.automation_profile_service
    cleveragents.cli.commands.lsp:cleveragents.application.lsp_service
```

### M9 Migration: Full A2A Adoption

In M9 (v3.8.0), the CLI will be fully migrated to use `A2aLocalFacade` for all local-mode commands:

```python
# Target pattern (M9)
from cleveragents.cli.a2a_local_facade import A2aLocalFacade

def plan_execute(plan_id: str):
    facade = A2aLocalFacade()
    facade.call("_cleveragents/plan.execute", {"plan_id": plan_id})
```

**Migration Steps**:

1. Implement `A2aLocalFacade` with full coverage of all `_cleveragents/` extension methods.
2. Measure performance overhead of local A2A routing (target: < 5ms per command).
3. Replace all direct service imports in CLI command handlers with `facade.call()`.
4. Remove all `# cli-exemption: local-only` annotations from import-linter config.
5. Remove the `ignore_imports` block from the import-linter contract.
6. Validate with full CLI integration test suite.
7. Update this ADR status to "Superseded" and reference the M9 implementation PR.

## Consequences

### Positive

- **Architectural consistency**: Local and server-mode CLI use the same protocol boundary.
- **Testability**: CLI tests mock the A2A facade rather than Application-layer internals.
- **Decoupling**: Application-layer internal API changes do not break the CLI as long as the A2A contract is preserved.
- **Import-linter clean**: No boundary violations in CI after M9 migration.

### Negative

- **Performance overhead**: Routing through A2A adds latency (estimated < 5ms for local stdio transport). Acceptable for interactive CLI use.
- **Migration effort**: All CLI command handlers must be refactored in M9.
- **Temporary inconsistency**: Until M9, local-mode CLI bypasses the A2A boundary while server-mode enforces it.

### Neutral

- The exemption is explicitly documented and tracked, preventing silent accumulation of additional violations.
- The import-linter configuration makes the exemption visible in CI output.

## References

- [ADR-001: Layered Architecture](ADR-001-layered-architecture.md)
- [ADR-047: A2A Standard Adoption](ADR-047-acp-standard-adoption.md)
- [ADR-048: Server Application Architecture](ADR-048-server-application-architecture.md)
- [Spec: M7 CLI Communication Pattern Migration](../specification.md#cli-communication-pattern-migration)
- Issue #9899: Invariant reconciliation multi-phase enforcement
- Issue #9859: ACMS thread-safety model documentation
