v2
CLI Documentation
Architecture
Composition Engine

Composition Engine

The Composition Engine is the "brain" of V2 that resolves V2Genome into executable modules.

Overview

The Composition Engine:

  1. Loads recipe books from marketplaces
  2. Expands packages into modules using recipes
  3. Resolves dependencies using prerequisites
  4. Generates lock file for reproducible builds

Architecture

V2Genome

CompositionEngine.resolve()

RecipeExpander.expand()      → Packages → Modules

DependencyResolver.resolve()  → Prerequisites → Dependencies

LockFileService.generate()    → Lock File

LockFile

Key Components

RecipeExpander

Expands business packages into technical modules:

// Input: packages: { auth: {} }
// Recipe book: auth → capabilities/auth
// Output: modules: [{ id: 'capabilities/auth', targetPackage: 'auth' }]

Process:

  1. For each package in V2Genome
  2. Look up package in recipe book
  3. Get module ID from recipe
  4. Create module with target package/app

DependencyResolver

Resolves module prerequisites into dependencies:

// Input: Module with prerequisites: ['database', 'auth']
// Recipe book: database → capabilities/database, auth → capabilities/auth
// Output: Dependencies: ['capabilities/database', 'capabilities/auth']

Process:

  1. For each module
  2. Resolve prerequisites to module IDs
  3. Build dependency graph
  4. Topological sort for execution order

LockFileService

Generates lock file for reproducible builds:

interface LockFile {
  version: string;
  resolvedAt: string;
  genomeHash: string;
  executionPlan: string[];  // Module IDs in execution order
  modules: Module[];
  marketplaces: Record<string, MarketplaceInfo>;
}

Purpose:

  • Reproducible builds
  • Execution order
  • Module metadata

Resolution Process

Step 1: Load Recipe Books

const recipeBooks = await loadRecipeBooks(genome.marketplaces);
// recipeBooks: Map<marketplaceName, RecipeBook>

Step 2: Expand Packages

const expandedModules = recipeExpander.expand(
  genome.packages,
  recipeBooks
);
// expandedModules: Module[] with targetPackage/targetApps

Step 3: Resolve Dependencies

const dependencyGraph = dependencyResolver.resolve(
  expandedModules,
  recipeBooks
);
// dependencyGraph: Dependency graph with execution order

Step 4: Generate Lock File

const lockFile = lockFileService.generate(
  genome,
  expandedModules,
  dependencyGraph
);
// lockFile: LockFile with execution plan

Example

Input V2Genome

{
  packages: {
    auth: {},
    payments: {}
  },
  apps: {
    web: {
      framework: 'nextjs',
      packages: ['auth', 'payments']
    }
  }
}

Recipe Book

{
  "packages": {
    "auth": {
      "providers": {
        "default": {
          "modules": [{ "id": "capabilities/auth", "targetPackage": "auth" }]
        }
      }
    },
    "payments": {
      "providers": {
        "default": {
          "modules": [{ "id": "capabilities/payments", "targetPackage": "payments" }]
        }
      }
    },
    "nextjs": {
      "providers": {
        "default": {
          "modules": [{ "id": "capabilities/nextjs", "targetApps": ["web"] }]
        }
      }
    }
  }
}

Output Lock File

{
  "executionPlan": [
    "capabilities/nextjs",
    "capabilities/auth",
    "capabilities/payments"
  ],
  "modules": [
    { "id": "capabilities/nextjs", "targetApps": ["web"] },
    { "id": "capabilities/auth", "targetPackage": "auth" },
    { "id": "capabilities/payments", "targetPackage": "payments" }
  ]
}

Framework Detection

Frameworks are detected from apps:

// App defines framework
apps: {
  web: { framework: 'nextjs' }
}
 
// Recipe book maps framework package → module
recipeBook.packages.nextjs → capabilities/nextjs
 
// Framework module has targetApps (not targetPackage)
{ id: 'capabilities/nextjs', targetApps: ['web'] }

Dependency Resolution

Dependencies are resolved from prerequisites:

// Module has prerequisites
module.prerequisites = ['database', 'auth']
 
// Recipe book maps prerequisites → modules
recipeBook.packages.database → capabilities/database
recipeBook.packages.auth → capabilities/auth
 
// Dependencies added
module.dependencies = ['capabilities/database', 'capabilities/auth']

Lock File Validation

Lock file is validated before use:

// Check if lock file matches current genome
const isValid = await lockFileService.isLockFileValid(
  projectRoot,
  genome
);
 
// If valid, reuse lock file (faster)
// If invalid, regenerate

Validation Checks:

  • Genome hash matches
  • Marketplace versions match
  • Package/app structure matches

Related