# How the Generator-Critic Split Is Implemented in ADHD: A Deep Dive Into the Source Code

> Explore the generator-critic split in ADHD source code. Discover how system prompts and runtime model selection mechanically implement generation and evaluation.

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

---

**The generator-critic split in ADHD is implemented mechanically through two distinct LLM system prompts (`DIVERGE_SYSTEM` for generation, `SCORE_SYSTEM` and `CLUSTER_SYSTEM` for evaluation) and optional separate model instances selected at runtime in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts).**

ADHD (Attention-Driven Hyperdivergence) is an open-source TypeScript framework for structured brainstorming that enforces cognitive separation between creative generation and critical evaluation. This article examines exactly how the **generator-critic split** works at the code level, tracing the implementation through model selection, prompt engineering, and execution orchestration in the UditAkhourii/adhd repository.

## Model Selection: Configuring Separate Generator and Critic Backends

The **generator-critic split** begins with model flexibility. In [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts), the `run` function accepts both a `model` parameter (for generation) and an optional `criticModel` parameter (for evaluation):

```ts
// src/engine.ts, lines 27-30
const critic = criticModel ?? model;   // ← critic may be a different model

```

This single line enables three distinct configurations:

- **Same model** — `criticModel` omitted; both phases use identical LLM backend
- **Different models** — `criticModel` specified; typically a more capable model for evaluation
- **Same model, different prompts** — model identical, but system prompts enforce role separation

The fallback pattern (`criticModel ?? model`) ensures backward compatibility while allowing power users to optimize each phase independently.

## Generator Phase: Enforcing Divergence Through `DIVERGE_SYSTEM`

The generator phase isolates **divergent thinking** through a strict system prompt. In [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts), the `DIVERGE_SYSTEM` constant constrains the LLM to pure idea generation:

```ts
// src/engine.ts, lines 61-69
const DIVERGE_SYSTEM = `You are in DIVERGENT mode. You are a generator, not a critic.
Rules:
- Output a JSON array only. No prose before/after.
- Generate the requested number of distinct ideas.
- STRICT RULE: Do NOT evaluate, rank, or critique ideas.
- Focus: breadth, novelty, and variety.`;

```

Key mechanical enforcements in this prompt:

- **Role identity** — explicit "generator, not a critic" declaration
- **Output format** — JSON array constraint prevents evaluative commentary
- **Prohibited behaviors** — explicit ban on ranking, scoring, or quality judgments

Each frame calls `callLLM` with this prompt during the `divergeBranch` execution, creating multiple parallel generation streams.

## Critic Phase: Parallel Evaluation With `SCORE_SYSTEM` and `CLUSTER_SYSTEM`

After divergence completes, the **critic** executes two passes in parallel, each with distinct system prompts designed for **convergent thinking**:

### Scoring Pass (`SCORE_SYSTEM`)

```ts
// src/engine.ts, lines 71-88
const SCORE_SYSTEM = `You are in CONVERGENT mode. You are now the critic.
Score each idea on three axes 0-10:
1. relevance (to the core problem)
2. novelty (originality, non-obviousness)
3. feasibility (can this be built/deployed reasonably?)`;

```

### Clustering Pass (`CLUSTER_SYSTEM`)

```ts
// src/engine.ts, lines 91-95
const CLUSTER_SYSTEM = `You group ideas into 3-6 clusters by their UNDERLYING ANGLE
or conceptual approach. Name each cluster with a short evocative title.`;

```

Both passes use the `critic` model instance (potentially different from the generator) and explicitly invoke evaluative cognitive modes.

## Execution Flow: Orchestrating the Split in `run()`

The **generator-critic split** is mechanically enforced through temporal sequencing and parallel execution patterns in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts):

```ts
// src/engine.ts, lines 52-63 and 66-70
// Phase 1: DIVERGE (generator)
const branches = await Promise.all(
  frames.map(frame => divergeBranch(problem, frame, model, ideasPerFrame))
);

// Phase 2: CONVERGE (critic) — parallel scoring and clustering
const [scoreMap, clusters] = await Promise.all([
  scoreIdeas(problem, allIdeas, critic),      // uses SCORE_SYSTEM
  clusterIdeas(problem, allIdeas, critic),    // uses CLUSTER_SYSTEM
]);

```

This architecture guarantees **no feedback loop** from critic to generator during the initial burst. The generator completes fully before any evaluation occurs—preventing premature convergence that would limit creative exploration.

## Practical Implementation: Running With Separate Models

Configure the **generator-critic split** explicitly by specifying both model parameters:

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

await run({
  problem: "Design a tool for remote pair-programming",
  model: "gpt-4o-mini",          // generator: fast, cost-effective
  criticModel: "gpt-4o",         // critic: stronger reasoning for evaluation
  framesPerRun: 4,
  ideasPerFrame: 5,
});

```

Inspect the role assignment in the engine source:

```ts
// Inside src/engine.ts execution
const critic = criticModel ?? model;

// Generator role
await callLLM({ model, systemPrompt: DIVERGE_SYSTEM, userPrompt });

// Critic roles
await callLLM({ model: critic, systemPrompt: SCORE_SYSTEM, ... });
await callLLM({ model: critic, systemPrompt: CLUSTER_SYSTEM, ... });

```

## Key Source Files

- **[`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts)** — Core orchestration: model selection, prompt constants (`DIVERGE_SYSTEM`, `SCORE_SYSTEM`, `CLUSTER_SYSTEM`), and the `run()` execution flow
- **[`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts)** — Cognitive frame definitions for the generator phase
- **[`src/llm.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/llm.ts)** — `callLLM` abstraction for model invocation
- **[`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts)** — TypeScript interfaces for models, branches, scores, and clusters

## Summary

- **Mechanical separation** — The split is enforced through distinct system prompts (`DIVERGE_SYSTEM` vs. `SCORE_SYSTEM`/`CLUSTER_SYSTEM`) rather than architectural components
- **Model flexibility** — Optional `criticModel` parameter in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) line 27 enables backend specialization without code changes
- **Temporal isolation** — Generator completes entirely before critic evaluation begins, preventing cognitive contamination
- **Parallel critique** — Scoring and clustering execute simultaneously via `Promise.all` for efficiency
- **Prompt-driven roles** — System instructions, not fine-tuning or separate code paths, define generator and critic behaviors

## Frequently Asked Questions

### Can I use the same model for both generator and critic phases?

Yes. The `criticModel` parameter is optional; if omitted, the framework falls back to the generator model via `const critic = criticModel ?? model` in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts). The **generator-critic split** is primarily enforced through prompt engineering rather than model separation.

### Why does the critic run scoring and clustering in parallel?

Parallel execution via `Promise.all([scoreIdeas(...), clusterIdeas(...)])` reduces latency without compromising quality. Both operations are read-only evaluations of the completed generator output, so no sequential dependency exists between them.

### How does `DIVERGE_SYSTEM` prevent the model from self-critiquing?

The prompt contains explicit constraints: "STRICT RULE: Do NOT evaluate, rank, or critique ideas" plus format restrictions (JSON array only) that make evaluative commentary structurally invalid. This is **prompt-level enforcement** rather than architectural blocking.

### What happens if I specify a weaker model as critic?

The framework will execute normally, but evaluation quality may degrade. The typical pattern uses equivalent or stronger models for the critic phase (e.g., `gpt-4o-mini` generator, `gpt-4o` critic) since judgment tasks often require more capability than generation tasks.