Clean Architecture
This document explains how the AI Primitives Hub packages follow Clean Architecture principles.
Terminology
- Domain Layer: The core business logic and domain models, independent of external concerns.
- Ports: Interfaces defined by the domain layer that specify what the domain needs from the outside world.
- Adapters: Implementations of ports that connect the domain to external systems (databases, APIs, file systems).
- Application Layer: Orchestrates use cases by coordinating domain objects and adapters.
- Infrastructure Layer: Provides concrete implementations of ports (GitHub client, file system, HTTP).
- Dependency Rule: Dependencies point inward — outer layers depend on inner layers, never the reverse.
Principles
Clean Architecture (also known as Hexagonal Architecture or Ports and Adapters) emphasizes:
- Independence of Frameworks: The architecture does not depend on the existence of external libraries or frameworks.
- Testability: Business rules can be tested without UI, database, web server, or any external element.
- Independence of UI: The UI can change easily, without changing the rest of the system.
- Independence of Database: You can swap out Oracle or MongoDB for another database without affecting business rules.
- Independence of External Agencies: Business rules don't know anything about the outside world.
What It Is
Clean Architecture organizes code into concentric layers. The innermost layer contains the domain entities and business rules. Outer layers contain mechanisms for delivering data to and from the domain. The key insight is that dependencies only point inward — the domain knows nothing about the infrastructure, but the infrastructure depends on the domain through well-defined interfaces (ports).
This is achieved through the Dependency Inversion Principle: high-level modules (domain) should not depend on low-level modules (infrastructure). Both should depend on abstractions (ports). The abstractions are owned by the domain layer, and the infrastructure layer provides concrete implementations (adapters).
In Our Case
The AI Primitives Hub packages follow Clean Architecture principles. The packages are organized as a pnpm workspace in packages/ with four layers:
Domain Layer (@ai-primitives-hub/core)
- Contains pure domain types:
Bundle,Collection,Primitive,Target,Source - Defines port interfaces in
ports/:FileSystem,HttpClient,GitHubApi,TargetWriter,BundleDownloader,BundleExtractor,SourceAdapter,LayoutConfigLoader,ResourceTransformer,AppStorage - No dependencies on other packages or external infrastructure
- Business rules live here (validation, parsing, domain logic)
Infrastructure Layer (@ai-primitives-hub/infra)
- Implements ports as adapters:
NodeHttpClient,GitHubApiClient,FileTreeTargetWriter,AdmZipBundleExtractor,LocalAdapter,GitHubAdapter,AwesomeCopilotAdapter,ApmAdapter,SkillsAdapter - Provides concrete implementations for external systems: GitHub API, file system, HTTP, ZIP extraction, per-target content writers
- Depends only on
@ai-primitives-hub/core(the port interfaces) - Can be swapped without affecting domain logic
Application Layer (@ai-primitives-hub/app)
- Orchestrates use cases: profile activation, bundle installation, registry management, discovery/search, multi-target transforms
- Coordinates domain objects and infrastructure adapters
- Contains no business rules — only orchestration
- Depends on core (domain) and infra (adapters)
- Also serves as the public SDK surface until a dedicated
@ai-primitives-hub/sdkpackage is needed
CLI Layer (@ai-primitives-hub/cli)
- Thin adapter that translates
ai-primitives-hubCLI commands into application use cases - Handles I/O, user interaction, and presentation using the Clipanion framework
- Depends on app, core, and infra but domain remains isolated
- Can be replaced with a web UI or a future dedicated SDK without changing core
VS Code Extension (Separate Delivery Mechanism)
The apps/vscode-extension package is the second delivery mechanism. It is being migrated onto the same core/infra/app layers through a strangler-fig approach (see ADR-0001) so that it stops duplicating business logic that already lives in app.
Dependency Flow
CLI → App → Infra → Core
Extension ↗ ↓
Core ←───┘
All dependencies point toward the core. The core defines interfaces (ports), and outer layers implement them (adapters). This allows us to:
- Test business logic without external dependencies
- Swap implementations (e.g., replace GitHub client with a mock)
- Add new delivery mechanisms (CLI, VS Code extension, web UI) without changing domain
- Evolve infrastructure independently of business rules
Further Reading
- Clean Architecture by Robert C. Martin — Original article introducing the concept
- Hexagonal Architecture by Alistair Cockburn — The original ports and adapters pattern
- Ports and Adapters Architecture — Practical explanation with examples
- Onion Architecture by Jeffrey Palermo — Another perspective on layered architecture
- Domain-Driven Design by Eric Evans — Foundation for domain-centric design
See Also
- Codemap — Package structure and dependency graph
- System Context — External relationships and user personas
- Container Diagram — High-level containers and technology choices
- Component Diagrams — Detailed component views