Dependency Resolution
Topological Sort & Capability Registry
The CLI uses graph-based dependency resolution to ensure modules execute in the correct order.
The Problem
Modules have dependencies:
{
id: 'connector/drizzle-nextjs',
requires: ['framework/nextjs', 'database/drizzle']
}Question: What order should modules execute?
Wrong order:
1. connector/drizzle-nextjs β Fails! Prerequisites missing
2. framework/nextjs
3. database/drizzle Correct order:
1. framework/nextjs β No prerequisites
2. database/drizzle β No prerequisites
3. connector/drizzle-nextjs β Prerequisites metSolution: Topological Sort
Dependency Graph
Implementation:
// src/core/services/dependency/dependency-graph.ts
export class DependencyGraph {
private nodes: Set<string> = new Set();
private edges: Map<string, Set<string>> = new Map();
addNode(id: string): void {
this.nodes.add(id);
}
addEdge(from: string, to: string): void {
// Edge: from β to (from must execute before to)
if (!this.edges.has(from)) {
this.edges.set(from, new Set());
}
this.edges.get(from)!.add(to);
}
topologicalSort(): string[] {
// Kahn's algorithm for topological sort
const inDegree = new Map<string, number>();
const queue: string[] = [];
const result: string[] = [];
// Calculate in-degrees
this.nodes.forEach(node => {
inDegree.set(node, 0);
});
this.edges.forEach((neighbors, node) => {
neighbors.forEach(neighbor => {
inDegree.set(neighbor, (inDegree.get(neighbor) || 0) + 1);
});
});
// Find nodes with no dependencies
inDegree.forEach((degree, node) => {
if (degree === 0) queue.push(node);
});
// Process queue
while (queue.length > 0) {
const node = queue.shift()!;
result.push(node);
this.edges.get(node)?.forEach(neighbor => {
const newDegree = (inDegree.get(neighbor) || 0) - 1;
inDegree.set(neighbor, newDegree);
if (newDegree === 0) {
queue.push(neighbor);
}
});
}
return result;
}
}Capability Registry (Prerequisite Validator)
Dynamic Capability Tracking
The PrerequisiteValidator acts as a dynamic capability registry:
export class PrerequisiteValidator {
private providedCapabilities: Set<string> = new Set();
// Track what's been installed
registerModule(blueprint: Blueprint): void {
blueprint.provides?.forEach(capability => {
this.providedCapabilities.add(capability);
});
}
// Validate prerequisites
validate(blueprint: Blueprint): ValidationResult {
const missing = blueprint.requires?.filter(
req => !this.providedCapabilities.has(req)
) || [];
if (missing.length > 0) {
return {
valid: false,
errors: [`Missing prerequisites: ${missing.join(', ')}`]
};
}
return { valid: true };
}
}Execution Pattern
const validator = new PrerequisiteValidator();
for (const module of executionOrder) {
const blueprint = loadBlueprint(module.id);
// Check prerequisites
const validation = validator.validate(blueprint);
if (!validation.valid) {
throw new Error(validation.errors.join(', '));
}
// Execute blueprint
await execute(blueprint);
// Register capabilities
validator.registerModule(blueprint);
}Key insight: Capabilities checked at runtime as modules execute, not statically.
Example: Execution Order Determination
Genome:
modules: [
{ id: 'ui/shadcn' }, // requires: framework
{ id: 'connector/drizzle-nextjs' }, // requires: framework, database
{ id: 'framework/nextjs' }, // requires: nothing
{ id: 'database/drizzle' } // requires: nothing
]Dependency Graph:
framework/nextjs βββ ui/shadcn
βββ connector/drizzle-nextjs
database/drizzle βββ connector/drizzle-nextjsTopological Sort Result:
1. framework/nextjs
2. database/drizzle
3. ui/shadcn
4. connector/drizzle-nextjsNatural property: Adapters always before connectors!
Parallel Execution Batching
The ExecutionPlanner creates batches of modules that can execute in parallel, significantly improving performance.
The Problem
Sequential execution is slow:
Module 1 (5s) β Module 2 (5s) β Module 3 (5s)
Total: 15 secondsBut some modules have no dependencies - they could run simultaneously!
The Solution: Batched Parallel Execution
Batch 1 (parallel): 5s
βββ framework/nextjs
βββ database/drizzle
βββ ui/shadcn-ui
Batch 2 (parallel): 5s
βββ connectors/drizzle-nextjs
βββ connectors/zustand-nextjs
Batch 3: 5s
βββ features/auth/tech-stack
Total: 15s β Same duration, but organized for future parallelizationImplementation
// ExecutionPlanner creates batches using topological levels
class ExecutionPlanner {
createExecutionPlan(): ExecutionPlan {
const batches: ExecutionBatch[] = [];
const levels = this.calculateTopologicalLevels(graph);
// Each level becomes a batch
levels.forEach((modules, level) => {
batches.push({
batchNumber: level + 1,
modules,
canExecuteInParallel: modules.length > 1,
estimatedDuration: this.estimateBatchDuration(modules),
dependencies: this.getBatchDependencies(modules)
});
});
return { batches, totalBatches: batches.length };
}
}Note: Current implementation executes batches sequentially but is architected for future parallel execution.
Feature Resolution System
When you request an abstract feature like features/auth, the CLI must resolve it to concrete implementations.
The Problem
Features have multiple implementations:
// User requests:
{ id: 'features/auth' }
// But which implementation?
// - Backend: better-auth-nextjs, clerk-nextjs, supabase-auth?
// - Frontend: auth-shadcn, auth-mui, auth-chakra?The Solution: Manifest-Driven Resolution
The CLI uses a three-step intelligent resolution process:
Step 1: Stack Detection
Extract the project's technology stack from genome modules:
// From genome modules:
modules: [
{ id: 'framework/nextjs' },
{ id: 'database/drizzle' },
{ id: 'ui/shadcn-ui' }
]
// Detected stack:
{
backend: ['nextjs', 'drizzle'],
frontend: ['shadcn', 'nextjs'],
ui: ['shadcn', 'tailwind']
}Step 2: Fetch Feature Manifest
Load the auto-generated feature manifest:
// features/auth/auth.manifest.json
{
"id": "auth",
"implementations": [
{
"type": "backend",
"stack": ["better-auth", "nextjs"],
"moduleId": "features/auth/backend/better-auth-nextjs"
},
{
"type": "frontend",
"stack": ["shadcn", "nextjs"],
"moduleId": "features/auth/frontend/shadcn"
},
{
"type": "tech-stack",
"moduleId": "features/auth/tech-stack"
}
]
}Step 3: Match & Return
// CLI resolves abstract feature to concrete modules:
[
{ id: 'features/auth/backend/better-auth-nextjs' },
{ id: 'features/auth/frontend/shadcn' },
{ id: 'features/auth/tech-stack' }
]Why This Matters:
User-friendly: Just request features/auth, CLI figures out the rest
Stack-aware: Automatically picks implementations that match your stack
Future-proof: Adding new implementations doesn't break existing genomes