Files
cleveragents-core/docs/adr/ADR-049-cli-communication-pattern.md
HAL9000 3975ad244c
CI / benchmark-publish (push) Failing after 35s
CI / lint (push) Successful in 53s
CI / quality (push) Successful in 1m9s
CI / typecheck (push) Successful in 1m14s
CI / build (push) Successful in 38s
CI / security (push) Successful in 1m21s
CI / push-validation (push) Successful in 22s
CI / helm (push) Successful in 38s
CI / integration_tests (push) Successful in 3m44s
CI / e2e_tests (push) Successful in 4m5s
CI / unit_tests (push) Failing after 6m56s
CI / docker (push) Has been skipped
CI / coverage (push) Successful in 11m16s
CI / status-check (push) Failing after 3s
CI / lint (pull_request) Successful in 1m15s
CI / build (pull_request) Successful in 54s
CI / quality (pull_request) Successful in 1m27s
CI / benchmark-publish (pull_request) Has been skipped
CI / typecheck (pull_request) Successful in 1m51s
CI / security (pull_request) Successful in 1m52s
CI / push-validation (pull_request) Successful in 20s
CI / helm (pull_request) Successful in 28s
CI / integration_tests (pull_request) Successful in 4m6s
CI / e2e_tests (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Successful in 4m54s
CI / docker (pull_request) Successful in 1m45s
CI / coverage (pull_request) Successful in 14m1s
CI / status-check (pull_request) Successful in 2s
docs(spec): fix invariant reconciliation, add ACMS thread safety, v3.6.0 section, ADR-049
- Fix invariant glossary entry: reconciliation now documented as occurring
  at each phase boundary (before Strategize, Execute, Apply, and after Apply)
  rather than only at start of Strategize (closes #9899)
- Add Multi-Phase Invariant Enforcement note to Plan Lifecycle section
- Add ACMS Thread Safety subsection documenting threading.RLock concurrency
  contract for ContextAssemblyPipeline and all context stores (closes #9859)
- Append M7: Advanced Concepts and Deferred Features (v3.6.0) milestone spec
  section covering advanced invariant lifecycle, ACMS observability, plan
  hierarchy enhancements, and CLI communication pattern migration
- Add ADR-049: CLI Communication Pattern documenting local CLI exemption
  from A2A boundary requirement and M9 migration path
2026-04-26 17:09:22 +00:00

6.6 KiB

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:

# 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:

[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:

# 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