Topological Sort

How Kahn's algorithm orders Kit execution across the spec graph — what batch groups are, how dependency resolution works, and how circular references are handled.

Topological Sort

Before any Kit runs, the generation pipeline must determine the order in which spec nodes should be processed. A service cannot be generated before the entities it depends on exist. An API endpoint cannot be generated before its service. A UI component cannot be generated before its data types.

computeTopologicalOrder(projectId) runs Kahn's algorithm over the spec graph's structural edges to produce a linearized build order where no node is processed before its dependencies.


Kahn's Algorithm

Kahn's algorithm processes a directed acyclic graph (DAG) by repeatedly removing nodes with no remaining in-edges (nodes whose dependencies have all been processed):

1. Compute in-degree for every node (count incoming dependency edges)
2. Initialize queue with all nodes whose in-degree = 0 (no dependencies)
3. While queue is not empty:
   a. Dequeue a node N
   b. Add N to the output order
   c. For each node M that N points to:
      - Decrement M's in-degree
      - If M's in-degree reaches 0, add M to the queue
4. If output order length < total nodes → cycle detected

The edges used for topological ordering are the spec graph's structural edges: contains, has_field, has_operation, flow_next, and implements. Semantic edges like guards or used_by are not used for ordering — they describe relationships, not dependencies.


Batch Groups

Kahn's algorithm naturally produces batches: groups of nodes that have no dependencies on each other and can be processed in parallel. The full generation pipeline uses 15 batches:

BatchTypeContents
0DeterministicScaffoldStep — package.json, tsconfig.json, Docker, .env template
1DeterministicSharedTypesStep — error types, response wrappers, utility types
1DeterministicDesignSystemStep — tailwind.config.ts, global CSS, theme tokens
2LLMEntityKit — Drizzle schema tables
2LLMSchemaKit — Zod validation schemas
2LLMGuardKit — auth/validation middleware
3LLMAuthKit — login, register, session, JWT
4DeterministicMigrationStep — drizzle-kit generate from schema files
5LLMServiceKit — service class skeletons
6LLMOperationKit — method implementations
7LLMEndpointKit — Hono route handlers
8LLMAPIClientKit — typed frontend client from endpoint contracts
9LLMComponentKit — React UI components
10LLMPageKit — Next.js pages
11LLMLayoutKit — app shell, navigation, layout wrapper
12LLMWorkflowKit, WorkflowStepKit, NotificationKit
13DeterministicTestInfraStep — Vitest config, test DB setup, test utilities
14DeterministicCICDStep — GitHub Actions, Dockerfile, Railway config

All Kits within the same batch number have no inter-dependencies and can execute concurrently. The BatchCoordinator dispatches them in parallel via the ContainerPlatform job queue.


What Nodes Enter the Sort

Only nodes with a spec node type enter the topological sort. These are the implementation targets:

  • spec_entity — domain entities (become Drizzle tables, service types, Zod schemas)
  • spec_api_endpoint — API routes (become Hono handlers)
  • spec_service — application services
  • spec_guard — access control definitions
  • spec_page / spec_component — UI elements
  • spec_workflow — Inngest workflow definitions

Each spec node maps to a KitType based on its artifact_type. The BatchCoordinator uses this mapping to route each node to the correct Kit.


Cycle Detection

If the spec graph contains a cycle — for example, entity A has a field referencing entity B, and entity B has a field referencing entity A — Kahn's algorithm will detect it:

After the sort completes, if outputOrder.length < totalNodes, some nodes were never added to the queue. Those nodes are in a cycle. The generation pipeline:

  1. Identifies the cycle members by diffing the output order against the full node set
  2. Returns them in a separate cycleGroups array in the TopologicalOrderResult
  3. Pauses the generation run and surfaces the cycle in the project dashboard

Cycles in the spec indicate a modeling error that must be resolved before generation can proceed. The fix is usually to introduce a reference field (a foreign key pointer) instead of embedding the full entity, breaking the circular dependency.


Dependency Resolution Details

Within a batch, nodes are independent by definition (no edges between them). Across batches, the ordering ensures:

  • Fields before entities that own themhas_field edges are traversed to determine entity processing order. If entity Order has a field of type Customer, Customer is placed in an earlier batch.
  • Entities before serviceshas_operation and uses edges ensure services run after all their entity dependencies.
  • Services before endpointsimplements edges ensure route handlers run after service definitions.
  • Types before components — UI component nodes run after all the data type nodes they depend on via props_type edges.

The result is a deterministic build order that matches how a human engineer would sequence the work: foundation first, then logic, then API surface, then UI.

Command Palette

Search for a command to run...