# 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