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
- 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
135 lines
6.6 KiB
Markdown
135 lines
6.6 KiB
Markdown
# 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
|