# ADHD Engine Architecture: Understanding the Diverge→Score→Cluster→Deepen Loop

> Explore the ADHD engine architecture's diverge score cluster deepen loop. Learn how this creative pipeline uses parallel LLM calls and weighted scoring to generate novel ideas.

- Repository: [Udit Akhouri/adhd](https://github.com/UditAkhourii/adhd)
- Tags: architecture
- Published: 2026-08-01

---

**The ADHD engine implements a four-stage creative pipeline—diverge, score, cluster, deepen—inside [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) to generate, evaluate, and expand non-obvious ideas using parallel LLM calls and weighted scoring.**

The **ADHD engine** is a TypeScript-based creative engine that transforms vague problem statements into structured, high-quality idea clusters. According to the UditAkhourii/adhd repository, the architecture separates wild generation from critical evaluation, enabling the `run()` function to orchestrate a complete creative-to-critical loop in a single execution.

## The Four-Stage Pipeline

The core `run()` function in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) orchestrates a strict sequence: **diverge** (generate), **score** (evaluate), **cluster** (group), and **deepen** (expand). Each stage corresponds to a specific LLM prompt and validation schema.

### Stage 1: Divergence (Parallel Generation)

The **diverge** stage generates raw ideas across multiple cognitive frames simultaneously. The `selectFrames` helper (defined in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts)) selects *N* frames—biased toward "code" tags when `codeMode` is enabled—and always injects at least one "wild" frame to force unconventional thinking.

For each selected frame, `divergeBranch` constructs a prompt using `DIVERGE_SYSTEM`, calls the LLM via `callLLM`, and parses the JSON array of ideas. Each idea is tagged with its frame ID for traceability. All branches execute concurrently via `p-limit` with a default concurrency of 4 to prevent rate-limiting while maximizing throughput.

```typescript
// From src/engine.ts - parallel divergence across frames
const branches = await Promise.all(
  frames.map(frame => divergeBranch(problem, frame, ideasPerFrame))
);

```

### Stage 2: Scoring (Convergent Evaluation)

Once raw ideas are collected, the **score** stage critically evaluates every leaf on three dimensions: **novelty**, **viability**, and **fit**. The `scoreIdeas` function sends the entire idea set to the LLM using `SCORE_SYSTEM` and parses the results against `ScoreRowSchema`.

The engine computes a weighted **total score** using the formula: `novelty * 0.35 + viability * 0.4 + fit * 0.25`. This weighting explicitly favors non-obvious but shippable ideas, storing results in a `Map<string, Score>` keyed by idea UUID.

### Stage 3: Clustering (Thematic Grouping)

The **cluster** stage shapes the solution space by grouping the top-scored ideas into 3–6 thematic clusters. The `clusterIdeas` function transmits the problem statement and idea list to the LLM with `CLUSTER_SYSTEM`, expecting a JSON array of clusters with `label` and `ideaIds` properties.

This step exposes the "shape" of the solution space rather than presenting isolated leaves, making it easier to identify dominant themes and gaps.

### Stage 4: Deepening (Focus and Expansion)

In the **deepen** stage, the engine selects the **top-K** ideas (sorted by total score) and expands each into a rich sketch plus child ideas. The `deepenIdea` function processes one idea at a time, returning a structured object containing:
- A detailed sketch (4–8 sentences)
- An array of child ideas with increased `depth` and a `parentId` referencing the original

```typescript
// From src/engine.ts - deepening top-K ideas
const deepened = await Promise.all(
  shortlist.slice(0, topK).map(idea => deepenIdea(idea, problem))
);

```

Optionally, the engine generates a **provocation** from the highest-novelty leaf (ignoring traps) to give the user a final creative nudge.

## Execution Flow and Concurrency

The loop executes in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) with clear separation of concerns: divergence and deepening run under `p-limit` concurrency controls, while scoring and clustering operate on the full dataset. The `run()` function optionally begins with `reframeProblem` to strip incidental anchors from the input before entering the main pipeline.

All LLM interactions flow through `callLLM` in [`src/llm.js`](https://github.com/UditAkhourii/adhd/blob/main/src/llm.js) and are validated against Zod schemas (`DivergeRowSchema`, `ScoreRowSchema`, `ClusterSchema`, `DeepenSchema`). Failures fall back to safe defaults—empty arrays or placeholder sketches—ensuring the pipeline remains robust against malformed JSON.

## Data Structures and Type Safety

The engine relies on strict TypeScript definitions in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts). Key interfaces include:
- **`Idea`**: Contains `id`, `text`, `frameId`, `depth`, and optional `parentId`
- **`Score`**: Tracks `novelty`, `viability`, `fit`, and computed `total`
- **`RunResult`**: Returns `branches`, `clusters`, `shortlist`, `deepened`, and `provocation`

## Implementation Example

To invoke the engine, import `run` from [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) and configure the options:

```typescript
import { run } from "./engine";

const result = await run({
  problem: "Add real-time collaborative editing to our note-app.",
  framesPerRun: 5,      // 5 divergent frames
  ideasPerFrame: 6,     // 6 ideas per frame
  topK: 3,              // Deepen top 3 ideas
  concurrency: 4,         // Parallel LLM calls
  codeMode: true,       // Bias toward code-related frames
});

console.log("Best pick:", result.nonObviousPick?.text);
console.log("Deepened sketches:", result.deepened.map(d => d.sketch));

```

## Summary

- The **diverge** stage uses `selectFrames` and `divergeBranch` to generate parallel ideas across multiple perspectives, always including a "wild" frame.
- The **score** stage evaluates ideas on novelty (35%), viability (40%), and fit (25%), storing weighted totals in a typed Map.
- The **cluster** stage groups ideas into 3–6 thematic clusters using `clusterIdeas` to reveal solution-space patterns.
- The **deepen** stage expands the top-K scored ideas into detailed sketches and child ideas with parent-child relationships.
- Concurrency is managed via `p-limit` (default 4), and all LLM outputs are validated against Zod schemas for type safety.

## Frequently Asked Questions

### What is the purpose of the frame system in ADHD?

Frames are cognitive perspectives defined in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts) that force the LLM into specific corners during divergence. When `codeMode` is enabled, the `selectFrames` function biases selection toward code-related tags while guaranteeing at least one "wild" frame appears in every run to ensure unconventional outputs.

### How does the scoring algorithm weight different criteria?

The `scoreIdeas` function computes a total score using fixed weights: **viability** at 40%, **novelty** at 35%, and **fit** at 25%. This prioritizes ideas that are technically feasible and original over those that merely match initial expectations.

### What happens during the deepening stage?

The `deepenIdea` function takes each top-K idea and prompts the LLM to write a 4–8 sentence sketch plus generate child ideas. These children become full `Idea` objects with incremented `depth` and a `parentId` linking back to the source, creating a hierarchical tree of concept variations.

### How does the engine handle concurrent LLM calls?

Both the divergence and deepening stages use `p-limit` to restrict concurrent LLM calls (defaulting to 4 simultaneous requests). This prevents API rate limits while still exploiting parallelism across frames or top-K ideas, with all async operations wrapped in `Promise.all` for efficiency.