Composition Root
The Composition Root is the single place where all concrete implementations are instantiated and wired together. This is the cornerstone of Dependency Inversion.
Location
Sources/App/CompositionRoot.swift
How It Works
@Observable
final class CompositionRoot {
// All services exposed as protocol types
private(set) var configProvider: any ConfigProviding
private(set) var themeProvider: any ThemeProviding
private(set) var persistence: any PersistenceProviding
private(set) var fleetManager: any FleetManaging
private(set) var costAggregator: any CostAggregating
private(set) var projectManager: any ProjectManaging
private(set) var hookEventParser: any HookEventParsing
private(set) var recorder: any SessionRecordable
init() {
// Phase 1: Infrastructure (no dependencies)
let persistence = DatabaseManager()
self.persistence = persistence
// Phase 2: Configuration
let configProvider = ConfigManager(yamlParser: YAMLParserImpl())
self.configProvider = configProvider
// Phase 3: Domain services
self.fleetManager = FleetManager()
self.costAggregator = CostEngine(persistence: persistence)
// ... etc
}
}
Initialization Phases
Services are initialized in dependency order:
- Infrastructure — persistence, YAML parser (no dependencies)
- Configuration — config manager (depends on YAML parser)
- Domain Services — fleet, cost, project, recording (depend on persistence + config)
- Integration — hook parser, MCP server (depend on domain services)
Rules
- Only
CompositionRootcreates concrete types — everywhere else uses protocols - No service locator pattern — dependencies are injected, not looked up
@Observable— the root itself is observable for SwiftUI environment injection- Stubs for incremental development — unimplemented services use stub implementations that compile but throw at runtime