Files
AirCoding/AirPlan/docs/architecture/c4/code-view.md
AirCoding 82f3140847 Initial commit: AirCoding V1.0.0 Alpha architecture baseline
Complete architecture document set with multi-model review remediation:
- Frozen interface contracts, runtime semantics, DB schemas
- Event/tool/error/provider registries
- Scheduler and main agent state machines
- C4 module/code views, solution architecture, baseline V1
- Multi-model review reports and joint assessment
- Phase-gate remediation complete (P0/P1/P2/UX resolved)
- Implementation plan with T-000A through T-045
- Reference folders kept as placeholders only
2026-05-28 18:45:01 +08:00

20 KiB

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:

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

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

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

@startuml
interface RuntimeEvent<T> {
  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<T> {
  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<I, O> {
  name: string
  version: number
  description: string
  input_schema: JsonSchema<I>
  output_schema: JsonSchema<O>
  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:

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

@startuml
class RuntimeApp {
  +start(options): Promise<void>
  +shutdown(): Promise<void>
}

class ServiceRegistry {
  +get<T>(token): T
  +register(token, service): void
}

class ProjectStore {
  +open(root): Promise<ProjectContext>
  +initialize(root): Promise<ProjectContext>
}

class SessionManager {
  +openSession(project, options): Promise<SessionContext>
  +closeSession(sessionId): Promise<void>
}

class DatabaseManager {
  +open(path): DatabaseHandle
  +transaction(fn): Promise<T>
}

class MigrationRunner {
  +migrate(db): Promise<void>
}

class EventStore {
  +append(event): Promise<void>
  +query(filter): Promise<RuntimeEvent[]>
}

class EventIngestor {
  +ingest(event): Promise<void>
  +ingest_ephemeral(event): Promise<void>
}

class EventBus {
  +publish(event): void
  +subscribe(filter, handler): Subscription
}

class ProjectionStore {
  +hydrate(sessionId): Promise<void>
  +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

@startuml
class Scheduler {
  +create_tasks(session_id, specs): Promise<void>
  +add_dependency(session_id, task_id, dependency): Promise<void>
  +load_graph(session_id): Promise<TaskGraph>
  +run_until_idle(session_id): Promise<SchedulerRunResult>
  +cancel_task(task_id, reason): Promise<void>
  -plan_wave(graph): SchedulerWavePlan
  -dispatch(wave): Promise<void>
  -collect_results(): Promise<void>
}

class TaskGraph {
  +tasks: Map<TaskID, TaskNode>
  +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<WorkspaceRef>
  +mergeWorkspace(workspaceId): Promise<MergeResult>
  +cleanupWorkspace(workspaceId): Promise<void>
}

class AgentMonitor {
  +recordHeartbeat(event): void
  +detectLostAgents(): Promise<AgentLost[]>
  +enforceTimeouts(): Promise<void>
}

class WorkerManager {
  +spawn(taskSpec, contextPack): Promise<WorkerProcess>
  +cancel(agentId, reason): Promise<void>
}

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

@startuml
class ToolRegistry {
  +register(definition, executor): void
  +call(name, input, context): Promise<ToolResultEnvelope>
  +list(): ToolDefinition[]
}

class PermissionEngine {
  +evaluate(request): Promise<PermissionDecision>
  +record(decision, context): Promise<void>
}

class PathClassifier {
  +classify(path, projectRoot): PathRiskClassification
}

class CommandRiskAnalyzer {
  +analyze(command, cwd): CommandRiskAnalysis
}

class CapabilityRegistry {
  +discover(): Promise<CapabilityManifestV1[]>
  +validate(manifest): Promise<ValidationResult>
  +enable(capability_id): Promise<void>
  +disable(capability_id): Promise<void>
  +register_tools(tool_registry): Promise<void>
}

class DoctorService {
  +run(input): Promise<DoctorRunOutput>
  +checkCapability(capability): Promise<DoctorIssue[]>
}

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

@startuml
class ContextAssembler {
  +assemble(input): Promise<AssembledContext>
  -loadLayers(profile): Promise<PromptLayer[]>
  -fitBudget(context): BudgetFitResult
}

class PromptLayerLoader {
  +loadRuntimeInvariant(): PromptLayer
  +loadRole(role): PromptLayer
  +loadProjectRules(project): PromptLayer[]
}

class MainAgent {
  +handleUserMessage(message): Promise<void>
  +presentProgress(): Promise<void>
  +presentBlocker(blocker): Promise<void>
}

class ArchitectureDesigner {
  +assessImpact(change): Promise<ArchitectureImpact>
  +updateArchitectureDocs(update): Promise<DocumentUpdate>
}

interface ProviderManager {
  +select_model(requirement): Promise<ModelAssignment>
  +complete(request): AsyncIterable<ProviderStreamEvent>
}

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<void>
  +lookup_by_signature(sig): Promise<DebugRecord[]>
  +lookup_by_task(task_id): Promise<DebugRecord[]>
  +update(id, patch): Promise<void>
}

class LearnedMemoryStore {
  +insert(memory): Promise<void>
  +lookup_by_type(type): Promise<LearnedMemory[]>
  +update_status(id, status): Promise<void>
  +scan_stale(): Promise<LearnedMemory[]>
}

class CompactionPolicy {
  +should_compact(messages, budget): boolean
  +compact(messages, target): Promise<CompactionResult>
}

ExperienceMinerRole --> LearnedMemoryStore
DebuggerRole --> DebugKnowledgeStore
ContextAssembler --> CompactionPolicy
@enduml

5. LLM Package Code View

Expected directory:

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

@startuml
interface ProviderAdapter {
  +provider_id: string
  +list_models(): Promise<ProviderCapabilityMatrix[]>
  +validate_model(model_id): Promise<ProviderCapabilityMatrix>
  +complete(input): AsyncIterable<ProviderStreamEvent>
  +count_tokens?(input): Promise<number>
}

class ProviderManager {
  +load_config(): Promise<void>
  +select_model(requirement): Promise<ModelAssignment>
  +complete(input): AsyncIterable<ProviderStreamEvent>
}

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:

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

@startuml
class CppToolRegistrar {
  +register(toolRegistry): void
}

class CppProjectDetector {
  +detect(projectRoot): Promise<CppDetectOutput>
}

class CMakeConfigurator {
  +configure(input): Promise<CppCmakeConfigureOutput>
}

class CppBuilder {
  +build(input): Promise<CppBuildOutput>
}

class CppTestRunner {
  +runTests(input): Promise<CppTestOutput>
}

class CppcheckRunner {
  +run(input): Promise<CppcheckOutput>
}

class ClangdClient {
  +query(input): Promise<ClangdQueryOutput>
}

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:

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

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

packages/cli/src/
  index.ts
  commands/
    run.ts
    init.ts
    doctor.ts
    provider.ts
    e2e.ts
    release.ts
  bootstrap/
    createRuntime.ts
    loadConfig.ts

UML

@startuml
class CliEntrypoint {
  +main(argv): Promise<number>
}

class RunCommand
class InitCommand
class DoctorCommand
class ProviderCommand
class E2ECommand
class ReleaseCommand
class RuntimeFactory {
  +create(options): Promise<RuntimeApp>
}

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/.

@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

@startuml
interface WorkerRole {
  +run(taskSpec, contextPack, runtime): Promise<WorkerResult>
}

class WorkerRuntime {
  +emit(event): void
  +callTool(name, input): Promise<ToolResultEnvelope>
  +checkpoint(data): Promise<void>
}

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:

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