# C4 Code View and UML Class Model Date: 2026-05-27 Status: Formal V1 code-view design for AirCoding V1.0.0 Alpha skeleton This document refines `AirPlan/docs/architecture/c4/module.md` from container/module view into package-level code structure, class/service responsibilities, UML class diagrams, and implementation boundaries. Canonical TypeScript interface contracts are defined in `AirPlan/docs/architecture/interface-contracts-v1.md`. ## 1. Code View Scope The V1.0.0 Alpha code view covers these packages: ```text packages/contracts packages/cli packages/runtime packages/llm packages/toolchain-cpp packages/tui ``` The code view is implementation-facing but remains architecture-only. It defines expected classes/interfaces and relationships; exact file names may be adjusted during implementation if contracts and dependencies remain stable. ## 2. Package Dependency Diagram ```plantuml @startuml skinparam componentStyle rectangle package "packages/contracts" as contracts package "packages/cli" as cli package "packages/runtime" as runtime package "packages/llm" as llm package "packages/toolchain-cpp" as cpp package "packages/tui" as tui cli --> runtime cli --> tui cli --> llm cli --> cpp runtime --> contracts runtime --> llm : adapter interfaces runtime ..> cpp : capability registration boundary llm --> contracts cpp --> contracts tui --> contracts runtime --> llm : ProviderManager facade/API @enduml ``` Rules: 1. `contracts` must have no implementation-package dependencies. 2. `runtime` must not import `tui`. 3. `tui` must depend only on `contracts` and a narrow `ProjectionClient`/UI API boundary; it must not import runtime private services, query SQLite, or subscribe to EventBus directly. 4. `toolchain-cpp` exposes tools through capability registration, not direct runtime coupling. 5. `llm` owns provider adapters, model config, provider conversion, and ProviderManager implementation; `runtime` owns prompt assembly and calls LLM through the provider facade/API. ## 3. Contracts Package Code View Expected directory: ```text packages/contracts/src/ index.ts ids.ts runtime.ts event.ts ipc.ts task.ts worker-result.ts tool.ts artifact.ts evidence.ts project.ts provider.ts permission.ts ui.ts error.ts capability.ts platform.ts ``` ### UML ```plantuml @startuml interface RuntimeEvent { id: UUID type: string version: number timestamp: ISOTimeString session_id: SessionID project_id?: ProjectID source: EventSource route: string[] payload: T } interface TaskSpec { id: TaskID type: TaskType title: string description: string acceptance_criteria: string[] scope: TaskScope dependencies: TaskDependencySpec[] verification: VerificationPolicy constraints: TaskConstraints context_refs: TaskContextRefs output_contract: WorkerOutputContract } interface WorkerResult { task_id: TaskID agent_id: AgentID agent_type: AgentType status: WorkerStatus summary: string changed_files: string[] artifacts: ArtifactRef[] verification: VerificationResult[] risks: Risk[] follow_up_tasks: FollowUpTask[] evidence_refs: EvidenceRef[] result: T } interface ToolDefinition { name: string version: number description: string input_schema: JsonSchema output_schema: JsonSchema category: ToolCategory permissions: ToolPermissionSpec streaming: boolean } interface ProviderCapabilityMatrix interface AirError interface ArtifactRef interface EvidenceRef interface PermissionDecision interface ProjectionSnapshot interface CapabilityManifestV1 RuntimeEvent --> EventSource TaskSpec --> WorkerResult : output contract WorkerResult --> ArtifactRef WorkerResult --> EvidenceRef ToolDefinition --> PermissionDecision AirError --> EvidenceRef @enduml ``` ### Contract Ownership | Contract | File | Primary consumers | |---|---|---| | IDs and aliases | `ids.ts` | all packages | | RuntimeEvent/EventSource | `event.ts` | EventStore, EventBus, IPC, ProjectionStore | | TaskSpec | `task.ts` | Scheduler, workers, ContextAssembler | | WorkerResult | `worker-result.ts` | workers, Scheduler, Main Agent | | ToolDefinition/ToolResult | `tool.ts` | ToolRegistry, capabilities, workers | | ArtifactRef/EvidenceRef | `artifact.ts`, `evidence.ts` | ArtifactStore, EvidenceStore, reports | | ProviderCapabilityMatrix | `provider.ts` | ProviderManager, Scheduler, Doctor | | AirError/ErrorKind | `error.ts` | tools, Scheduler, agents, UI | | IpcMessage/ControlMessage | `ipc.ts` | WorkerManager, child workers | | PermissionDecision | `permission.ts` | PermissionEngine, ToolRegistry, UI | | ProjectionSnapshot | `ui.ts` | ProjectionStore, TUI/HUD | | CapabilityManifestV1 | `capability.ts` | CapabilityRegistry, Doctor | ## 4. Runtime Package Code View Expected directory: ```text packages/runtime/src/ index.ts app/ RuntimeApp.ts ServiceRegistry.ts config/ ConfigLoader.ts ResourceLoader.ts project/ ProjectLocator.ts ProjectInitializer.ts ProjectStore.ts storage/ DatabaseManager.ts MigrationRunner.ts repositories/ events/ EventBus.ts EventStore.ts EventIngestor.ts EventSchemaRegistry.ts sessions/ SessionManager.ts SessionStore.ts scheduler/ Scheduler.ts TaskGraph.ts WavePlanner.ts RetryPlanner.ts WorkspaceManager.ts AgentMonitor.ts workers/ WorkerManager.ts WorkerProcess.ts WorkerProtocol.ts roles/ tools/ ToolRegistry.ts BuiltInToolRegistrar.ts fs/ shell/ git/ project/ artifact/ context/ permission/ doctor/ security/ PermissionEngine.ts PathClassifier.ts CommandRiskAnalyzer.ts SecretRedactor.ts capabilities/ CapabilityRegistry.ts CapabilityManifestValidator.ts context/ ContextAssembler.ts PromptLayerLoader.ts CompactionPolicy.ts artifacts/ ArtifactStore.ts EvidenceStore.ts knowledge/ DebugKnowledgeStore.ts LearnedMemoryStore.ts projection/ ProjectionStore.ts projections/ doctor/ DoctorService.ts checks/ logging/ Logger.ts DeveloperLogEncryptor.ts agents/ main/ architecture/ ``` ### Runtime Service UML ```plantuml @startuml class RuntimeApp { +start(options): Promise +shutdown(): Promise } class ServiceRegistry { +get(token): T +register(token, service): void } class ProjectStore { +open(root): Promise +initialize(root): Promise } class SessionManager { +openSession(project, options): Promise +closeSession(sessionId): Promise } class DatabaseManager { +open(path): DatabaseHandle +transaction(fn): Promise } class MigrationRunner { +migrate(db): Promise } class EventStore { +append(event): Promise +query(filter): Promise } class EventIngestor { +ingest(event): Promise +ingest_ephemeral(event): Promise } class EventBus { +publish(event): void +subscribe(filter, handler): Subscription } class ProjectionStore { +hydrate(sessionId): Promise +apply(event): void +snapshot(): ProjectionSnapshot } RuntimeApp --> ServiceRegistry RuntimeApp --> ProjectStore RuntimeApp --> SessionManager SessionManager --> DatabaseManager DatabaseManager --> MigrationRunner EventIngestor --> EventStore : durable events EventIngestor --> EventBus : ephemeral events EventStore --> DatabaseManager EventStore --> EventBus : publishes after commit ProjectionStore --> SessionStore : hydrate via repositories ProjectionStore --> EventBus : subscribes to live events @enduml ``` ### Scheduler UML ```plantuml @startuml class Scheduler { +create_tasks(session_id, specs): Promise +add_dependency(session_id, task_id, dependency): Promise +load_graph(session_id): Promise +run_until_idle(session_id): Promise +cancel_task(task_id, reason): Promise -plan_wave(graph): SchedulerWavePlan -dispatch(wave): Promise -collect_results(): Promise } class TaskGraph { +tasks: Map +dependencies: TaskDependencyRecord[] +getRunnableTasks(): TaskNode[] +markTerminal(taskId, status): void } class WavePlanner { +plan(graph, resources): SchedulerWavePlan } class RetryPlanner { +decide(task, attempts, error): RetryDecision } class WorkspaceManager { +createWorkspace(plan): Promise +mergeWorkspace(workspaceId): Promise +cleanupWorkspace(workspaceId): Promise } class AgentMonitor { +recordHeartbeat(event): void +detectLostAgents(): Promise +enforceTimeouts(): Promise } class WorkerManager { +spawn(taskSpec, contextPack): Promise +cancel(agentId, reason): Promise } class WorkerProcess { +agent_id: AgentID +pid?: number +send(envelope): void +on_message(handler): void } Scheduler --> TaskGraph Scheduler --> WavePlanner Scheduler --> RetryPlanner Scheduler --> WorkspaceManager Scheduler --> AgentMonitor Scheduler --> WorkerManager Scheduler --> EventStore Scheduler --> ContextAssembler WorkerManager --> WorkerProcess @enduml ``` ### Tool/Permission UML ```plantuml @startuml class ToolRegistry { +register(definition, executor): void +call(name, input, context): Promise +list(): ToolDefinition[] } class PermissionEngine { +evaluate(request): Promise +record(decision, context): Promise } class PathClassifier { +classify(path, projectRoot): PathRiskClassification } class CommandRiskAnalyzer { +analyze(command, cwd): CommandRiskAnalysis } class CapabilityRegistry { +discover(): Promise +validate(manifest): Promise +enable(capability_id): Promise +disable(capability_id): Promise +register_tools(tool_registry): Promise } class DoctorService { +run(input): Promise +checkCapability(capability): Promise } ToolRegistry --> PermissionEngine ToolRegistry --> EventIngestor ToolRegistry --> ArtifactStore PermissionEngine --> PathClassifier PermissionEngine --> CommandRiskAnalyzer PermissionEngine --> EventIngestor CapabilityRegistry --> ToolRegistry : registers enabled tools DoctorService --> CapabilityRegistry : reads manifests/checks dependencies @enduml ``` ### Context/Agent UML ```plantuml @startuml class ContextAssembler { +assemble(input): Promise -loadLayers(profile): Promise -fitBudget(context): BudgetFitResult } class PromptLayerLoader { +loadRuntimeInvariant(): PromptLayer +loadRole(role): PromptLayer +loadProjectRules(project): PromptLayer[] } class MainAgent { +handleUserMessage(message): Promise +presentProgress(): Promise +presentBlocker(blocker): Promise } class ArchitectureDesigner { +assessImpact(change): Promise +updateArchitectureDocs(update): Promise } interface ProviderManager { +select_model(requirement): Promise +complete(request): AsyncIterable } ContextAssembler --> PromptLayerLoader MainAgent --> ContextAssembler MainAgent --> ProviderManager : LLM facade from packages/llm MainAgent --> Scheduler ArchitectureDesigner --> ContextAssembler ArchitectureDesigner --> ProviderManager : LLM facade from packages/llm ArchitectureDesigner --> EventIngestor class DebugKnowledgeStore { +insert(record): Promise +lookup_by_signature(sig): Promise +lookup_by_task(task_id): Promise +update(id, patch): Promise } class LearnedMemoryStore { +insert(memory): Promise +lookup_by_type(type): Promise +update_status(id, status): Promise +scan_stale(): Promise } class CompactionPolicy { +should_compact(messages, budget): boolean +compact(messages, target): Promise } ExperienceMinerRole --> LearnedMemoryStore DebuggerRole --> DebugKnowledgeStore ContextAssembler --> CompactionPolicy @enduml ``` ## 5. LLM Package Code View Expected directory: ```text packages/llm/src/ index.ts ProviderManager.ts ModelConfigLoader.ts CapabilityMatrix.ts ConversionReport.ts adapters/ AnthropicAdapter.ts OpenAICompatibleAdapter.ts canonical/ AnthropicCanonical.ts ToolUseConverter.ts StreamNormalizer.ts ``` ### UML ```plantuml @startuml interface ProviderAdapter { +provider_id: string +list_models(): Promise +validate_model(model_id): Promise +complete(input): AsyncIterable +count_tokens?(input): Promise } class ProviderManager { +load_config(): Promise +select_model(requirement): Promise +complete(input): AsyncIterable } class ModelConfigLoader class CapabilityMatrixRegistry class AnthropicAdapter class OpenAICompatibleAdapter class AnthropicCanonicalConverter class StreamNormalizer ProviderManager --> ProviderAdapter ProviderManager --> ModelConfigLoader ProviderManager --> CapabilityMatrixRegistry AnthropicAdapter ..|> ProviderAdapter OpenAICompatibleAdapter ..|> ProviderAdapter OpenAICompatibleAdapter --> AnthropicCanonicalConverter ProviderAdapter --> StreamNormalizer @enduml ``` ## 6. Toolchain C++ Package Code View Expected directory: ```text packages/toolchain-cpp/src/ index.ts capability.ts CppToolRegistrar.ts detect/ CppProjectDetector.ts build/ CMakeConfigurator.ts CppBuilder.ts test/ CppTestRunner.ts analysis/ CppcheckRunner.ts ClangdClient.ts DiagnosticParser.ts ``` ### UML ```plantuml @startuml class CppToolRegistrar { +register(toolRegistry): void } class CppProjectDetector { +detect(projectRoot): Promise } class CMakeConfigurator { +configure(input): Promise } class CppBuilder { +build(input): Promise } class CppTestRunner { +runTests(input): Promise } class CppcheckRunner { +run(input): Promise } class ClangdClient { +query(input): Promise } class DiagnosticParser { +parse_compiler_output(output): Diagnostic[] +semantic_signature(diagnostic): string } CppToolRegistrar --> CppProjectDetector CppToolRegistrar --> CMakeConfigurator CppToolRegistrar --> CppBuilder CppToolRegistrar --> CppTestRunner CppToolRegistrar --> CppcheckRunner CppToolRegistrar --> ClangdClient CMakeConfigurator --> DiagnosticParser CppBuilder --> DiagnosticParser CppTestRunner --> DiagnosticParser CppcheckRunner --> DiagnosticParser @enduml ``` ## 7. TUI Package Code View Expected directory: ```text packages/tui/src/ index.ts TuiApp.tsx ProjectionClient.ts components/ SessionView.tsx TaskListView.tsx AgentStatusView.tsx ToolRunView.tsx DiffView.tsx EvidenceView.tsx PermissionPrompt.tsx BlockerReport.tsx HudView.tsx theme/ theme.ts keymap/ keymap.ts ``` ### UML ```plantuml @startuml class TuiApp { +start(): void +stop(): void } class ProjectionClient { +subscribe(handler): Subscription +snapshot(): ProjectionSnapshot } class SessionView class TaskListView class AgentStatusView class ToolRunView class EvidenceView class PermissionPrompt class BlockerReport class HudView TuiApp --> ProjectionClient TuiApp --> SessionView TuiApp --> TaskListView TuiApp --> AgentStatusView TuiApp --> ToolRunView TuiApp --> EvidenceView TuiApp --> PermissionPrompt TuiApp --> BlockerReport TuiApp --> HudView @enduml ``` Rules: 1. UI components render projections only. 2. Permission prompts emit user decisions through the narrow runtime UI command API, not private runtime services. 3. UI never mutates domain tables directly. 4. UI never imports `packages/runtime/src/*` private implementation modules. 5. Diff/evidence views must link back to artifact/evidence refs. ## 8. CLI Package Code View Expected directory: ```text packages/cli/src/ index.ts commands/ run.ts init.ts doctor.ts provider.ts e2e.ts release.ts bootstrap/ createRuntime.ts loadConfig.ts ``` ### UML ```plantuml @startuml class CliEntrypoint { +main(argv): Promise } class RunCommand class InitCommand class DoctorCommand class ProviderCommand class E2ECommand class ReleaseCommand class RuntimeFactory { +create(options): Promise } CliEntrypoint --> RunCommand CliEntrypoint --> InitCommand CliEntrypoint --> DoctorCommand CliEntrypoint --> ProviderCommand CliEntrypoint --> E2ECommand CliEntrypoint --> ReleaseCommand RunCommand --> RuntimeFactory InitCommand --> RuntimeFactory DoctorCommand --> RuntimeFactory @enduml ``` ## 9. Repository Interface Code View Domain repositories live under `packages/runtime/src/storage/repositories/`. ```plantuml @startuml interface SessionRepository interface MessageRepository interface EventRepository interface TaskRepository interface AgentRepository interface ToolRunRepository interface CommandRunRepository interface ArtifactRepository interface DiagnosticRepository interface EvidenceRepository interface WorkspaceRepository interface SummaryRepository interface UiStateRepository class SessionStore { +sessions: SessionRepository +messages: MessageRepository +events: EventRepository +tasks: TaskRepository +agents: AgentRepository +toolRuns: ToolRunRepository +commandRuns: CommandRunRepository +artifacts: ArtifactRepository +diagnostics: DiagnosticRepository +evidence: EvidenceRepository +workspaces: WorkspaceRepository +summaries: SummaryRepository +uiState: UiStateRepository } @enduml ``` Repositories must be thin persistence adapters. Scheduling, permission, and projection logic must not be hidden inside repositories. ## 10. Worker Role Code View ```plantuml @startuml interface WorkerRole { +run(taskSpec, contextPack, runtime): Promise } class WorkerRuntime { +emit(event): void +callTool(name, input): Promise +checkpoint(data): Promise } class ExecutorRole class ReviewerRole class DebuggerRole class CompactorRole class ExperienceMinerRole ExecutorRole ..|> WorkerRole ReviewerRole ..|> WorkerRole DebuggerRole ..|> WorkerRole CompactorRole ..|> WorkerRole ExperienceMinerRole ..|> WorkerRole WorkerRole --> WorkerRuntime @enduml ``` Role constraints: | Role | Write access | Required output | |---|---|---| | Executor | scoped project writes | ExecutorResult in WorkerResult | | Reviewer | read-only | ReviewerResult | | Debugger | scoped writes only when assigned | DebuggerResult | | Compactor | summaries/artifacts only | CompactorResult | | ExperienceMiner | candidates/rules/skills only when assigned | ExperienceMinerResult | ## 11. State Ownership Rules | State | Owner | Access rule | |---|---|---| | session DB | SessionStore/EventStore | runtime services only | | live events | EventBus | runtime services publish/subscribe | | UI projections | ProjectionStore | TUI read only | | artifacts | ArtifactStore | tools/workers via runtime API | | evidence refs | EvidenceStore | reports/reviews/debug via runtime API | | tasks/agents | Scheduler | repositories are storage only | | permission decisions | PermissionEngine | ToolRegistry requests decisions | | model config | ProviderManager | runtime/Doctor read through API | | project rules | ContextAssembler/ProjectStore | workers receive context excerpts | ## 12. Implementation Cut Lines V1.0.0 Alpha implementation must create public interfaces matching `interface-contracts-v1.md`. Classes may be implemented as functions/modules where idiomatic TypeScript is simpler, but module ownership, dependency direction, and service boundaries must remain intact. Do not implement: ```text TUI direct DB access worker direct SQLite writes capability direct dependency install provider adapter changing prompt semantics silently tool execution without PermissionEngine repositories containing scheduling policy ```