# How the Two-Phase Loop in ADHD Enforces Convergence Only After Divergence

> Discover how the ADHD two-phase loop enforces convergence after divergence by separating idea generation and evaluation. Learn more about this innovative approach.

- Repository: [Udit Akhouri/adhd](https://github.com/UditAkhourii/adhd)
- Tags: deep-dive
- Published: 2026-07-30

---

**The ADHD two-phase loop mechanically isolates idea generation from evaluation by spawning N parallel, stateless LLM branches with hard-wall prompts that forbid any scoring or ranking, then sequentially runs a single "critic" pass that performs the only convergence step after all divergent outputs are collected.**

The `UditAkhourii/adhd` repository implements an **Adaptive Divergent-then-Convergent Heuristic** that solves creative reasoning problems by strictly separating exploration from judgment. Understanding how the two-phase loop in ADHD enforces convergence only after divergence requires examining the mechanical isolation built into the TypeScript orchestration layer. The architecture guarantees that no evaluation leakage occurs during the generation phase by enforcing separation at the API-call level.

## Phase 1: Strict Divergence Through Isolated Branch Generation

### Parallel Stateless Sessions

In [`src/diverge.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/diverge.ts), the system samples **N cognitive frames** from the frame library and launches parallel generation calls via `Promise.all`. Each branch invokes `callLLM()` with a unique system prompt containing only the problem description, the selected frame's "vantage" prompt, and a hard-wall instruction that explicitly **forbids evaluation, ranking, or hedging**.

According to the implementation in [`src/diverge.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/diverge.ts), each branch executes as a fresh Claude Agent SDK session. This means there is **no shared KV-cache, no shared message history, and no cross-branch context**. Consequently, `branches[i]` never sees `branches[j]` during divergence—by construction. The raw JSON output from each branch contains only generative ideas without any comparative analysis.

### The Hard-Wall Guarantee

The hard-wall prompt acts as a **mechanical barrier** rather than a gentle suggestion. By explicitly instructing the model that evaluation is forbidden and requiring a pure JSON array output, the system ensures that the divergent phase remains pure generation. Because each branch runs in isolation, there is no possibility of early convergence through implicit comparison or ranking.

## Phase 2: Controlled Convergence Through the Critic Pipeline

### The Three-Pass Evaluation Structure

Once the divergent phase completes, [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) triggers the convergent phase through a single critic LLM call that executes three sequential passes defined in separate modules:

- **Score** ([`src/score.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/score.ts)): Rates every leaf on novelty, viability, and fit (0-10 each), tagging traps with concrete reasons.
- **Cluster** ([`src/cluster.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/cluster.ts)): Groups leaves by underlying design angle rather than surface keywords.
- **Deepen** ([`src/deepen.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/deepen.ts)): Expands the top-K non-trap leaves with sketches, risk analysis, and child ideas.

### Inverted System Prompts for Evaluation

The critic uses an **inverted system prompt** that forces evaluation mode—a stark contrast to the generation prompts. This design in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) represents the **only point** in the pipeline where pruning and selection occur, ensuring that convergence never interferes with the earlier exploration. The critic consumes all previous outputs from the `branches` array, performing structured analysis only after the full solution space has been explored.

## Mechanical Enforcement in the Orchestration Layer

### API-Level Separation

The enforcement happens at the function call level, not merely through prompt engineering. [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) distinctly separates the `Promise.all` block (divergent) from the sequential critic calls (convergent). The generator-critic split uses distinct functions with distinct system prompts, eliminating inadvertent leakage of evaluation information into the generation stage.

### Implementation Example

The orchestration code explicitly sequences the phases:

```ts
// Divergent phase – fire N parallel branches, each with a hard-wall prompt
const branches = await Promise.all(
  frames.map(frame =>
    withSemaphore(concurrency, () => callLLM({
      systemPrompt: `${frame.vantage}\n\nFORBIDDEN: evaluation, ranking, hedging. JSON array out.`,
      userPrompt:   `${problem}\n\n${context ?? ""}`,
    }))
  )
);
// No branch ever sees another branch's output – isolation is guaranteed

// Convergent phase – single critic call runs three passes
const scored = await scoreLeaves(branches);
const clustered = await clusterByAngle(scored);
const deepened = await deepenTopK(clustered, K);

```

This code demonstrates the mechanical separation: the first block spawns isolated generators, while the second block performs the only convergent evaluation.

## Summary

- **Mechanical isolation** at the API-call level prevents any evaluation during the divergent phase.
- **Stateless parallel branches** in [`src/diverge.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/diverge.ts) run with hard-wall prompts that forbid ranking or hedging.
- **Single critic pipeline** in Phase 2 ([`src/score.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/score.ts), [`src/cluster.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/cluster.ts), [`src/deepen.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/deepen.ts)) performs the only convergence after all divergent outputs are collected.
- **Three-pass evaluation** (Score, Cluster, Deepen) ensures structured convergence only after full exploration.
- **Temporal barrier** in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) guarantees convergent functions execute only after `Promise.all` resolves.

## Frequently Asked Questions

### How does ADHD prevent premature convergence during idea generation?

ADHD uses **hard-wall system prompts** in [`src/diverge.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/diverge.ts) that explicitly forbid evaluation keywords and hedging language. Combined with stateless LLM sessions where each branch operates in isolation without shared context or KV-cache, the architecture physically prevents the model from comparing or ranking ideas during the generation phase.

### What ensures that the critic phase only runs after divergence completes?

The orchestration logic in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) uses `Promise.all` to wait for all parallel divergent branches to return before invoking the sequential critic functions (`scoreLeaves`, `clusterByAngle`, `deepenTopK`). This creates a strict temporal barrier where convergence functions cannot execute until the `branches` array is fully populated.

### Why are the Score, Cluster, and Deepen operations separated into different files?

Separating these concerns into [`src/score.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/score.ts), [`src/cluster.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/cluster.ts), and [`src/deepen.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/deepen.ts) allows each pass to use specialized system prompts and logic. This modular approach prevents the critic from conflating evaluation (scoring), synthesis (clustering), and expansion (deepening), ensuring that each convergence step remains methodologically distinct and traceable.

### Can the number of divergent branches (N) be configured?

Yes. The **N** parameter representing the number of cognitive frames is configurable. The system samples this configurable number of frames from the frame library and maps them to parallel LLM calls via the `frames.map()` operation in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts), allowing users to scale the breadth of divergence according to problem complexity.