# How to Use the `criticModel` Option for Separate Scoring and Clustering in ADHD

> Unlock separate scoring and clustering in ADHD with the criticModel option. Learn how to configure RunOptions for distinct LLM usage in convergence and divergence phases.

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

---

**Set the `criticModel` option in your `RunOptions` to use a different LLM for the convergence phase (scoring and clustering) while keeping the divergence phase on the original model.**

The ADHD framework separates creative idea generation from critical evaluation through a two-phase architecture. By default, both phases use the same language model, but the `criticModel` option allows you to offload scoring and clustering to a distinct model. This is particularly useful when you want to use a high-performance model for generation and a cost-effective model for evaluation.

## Understanding ADHD’s Two-Phase Architecture

ADHD’s engine operates through two distinct stages:

- **Divergence** – Parallel generator calls produce raw ideas using the primary model.
- **Convergence** – A critic pass **scores** each idea and **clusters** them into logical groups.

By default, the critic uses the same LLM specified in the `model` parameter. However, sourcing a separate `criticModel` lets you optimize for cost or latency during the evaluation phase without sacrificing generation quality.

## How `criticModel` Works in the Source Code

The separation of concerns is implemented in three core files:

### Type Definition in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts)

The `RunOptions` interface declares `criticModel` as an optional string that overrides the default model only for scoring and clustering:

```typescript
export type RunOptions = {
  // ...
  model?: string;            // generator + critic default
  criticModel?: string;      // overrides model **only** for scoring & clustering
  // ...
};

```

### Engine Implementation in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts)

The `run` function resolves the effective critic model using a nullish coalescing operator. If `criticModel` is provided, it takes precedence; otherwise, it falls back to the main `model`:

```typescript
const critic = criticModel ?? model;   // uses criticModel if provided

const [scoreMap, clusters] = await Promise.all([
  scoreIdeas(problem, allIdeas, critic),   // scoring uses critic
  clusterIdeas(problem, allIdeas, critic), // clustering uses critic
]);

```

Both `scoreIdeas` and `clusterIdeas` receive the resolved `critic` variable and internally call the LLM via `callLLM` (defined in [`src/llm.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/llm.ts)). The generator calls in the divergence phase remain unaffected by this setting.

## Code Examples

### Default Behavior (Same Model for Both Phases)

When you omit `criticModel`, the engine uses the specified `model` for generation, scoring, and clustering:

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

await run({
  problem: "Add real-time collaborative editing to our note-taking app",
  model: "claude-3-5-sonnet-20240620",   // used for both phases
});

```

### Using a Separate Critic Model

To use a cheaper or faster model for evaluation while keeping generation on a premium model:

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

await run({
  problem: "Add real-time collaborative editing to our note-taking app",
  model: "claude-3-5-sonnet-20240620",   // generator only
  criticModel: "gpt-4o-mini",            // scoring & clustering only
});

```

In this configuration, idea generation runs on Claude 3.5 Sonnet, while the convergence phase (scoring and clustering) executes on GPT-4o-mini.

### Debugging with Event Logging

Verify that the correct model is being used by attaching an event listener:

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

await run({
  problem: "Add real-time collaborative editing to our note-taking app",
  model: "claude-3-5-sonnet-20240620",
  criticModel: "gpt-4o-mini",
  onEvent: (e) => console.log("[ADHD]", e),
});

```

The `onEvent` callback emits progress events such as `score:done` and `cluster:done`, confirming that the critic pass used the overridden model.

## When to Use a Separate Critic Model

Consider configuring `criticModel` in the following scenarios:

- **Cost optimization** – Use an expensive, high-capability model for generation and a cheaper model for evaluation.
- **Latency reduction** – Deploy a faster model for clustering large idea sets without regenerating content.
- **Evaluation consistency** – Standardize on a specific judge model across different generation experiments to ensure consistent scoring baselines.

## Summary

- The `criticModel` option in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts) allows you to specify a distinct LLM for the convergence phase.
- In [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts), the engine resolves the critic model with `criticModel ?? model` and passes it to `scoreIdeas` and `clusterIdeas`.
- The divergence phase (idea generation) always uses the primary `model` parameter, regardless of `criticModel` settings.
- Event logging via `onEvent` confirms which model handles scoring and clustering operations.

## Frequently Asked Questions

### What happens if I don't specify a `criticModel`?

If `criticModel` is undefined, the engine defaults to using the value provided in the `model` parameter for both generation and evaluation. This ensures backward compatibility and consistent behavior when only one model is intended for the entire pipeline.

### Can I use any LLM provider for the `criticModel`?

Yes, as long as the model string is supported by the underlying `callLLM` implementation in [`src/llm.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/llm.ts). The ADHD framework uses the Claude Agent SDK internally, so any model identifier valid within that SDK (or your configured provider) works for the critic pass.

### Does `criticModel` affect the idea generation phase?

No. The `criticModel` parameter only influences the convergence phase. The divergence phase—where parallel generator calls produce raw ideas—strictly uses the `model` parameter specified in `RunOptions`. This separation ensures that creative generation remains consistent while evaluation strategies can vary.

### How can I verify which model is being used for scoring?

Attach an `onEvent` callback to your `run` invocation. The framework emits structured events including `score:done` and `cluster:done`. While these events don't explicitly name the model in the current implementation, you can inspect network calls or add custom logging inside [`src/llm.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/llm.ts) to confirm which model identifier is being passed to `scoreIdeas` and `clusterIdeas`.