How Cognitive Frames Are Defined and Used in ADHD: A Complete Technical Guide

Cognitive frames in ADHD are TypeScript objects that inject "vantage-point" system prompts into divergent LLM reasoning branches, forcing the model to explore solutions from 15+ distinct perspectives such as hardware engineer, 10-year-old, or adversarial hacker.

This deep dive examines how the ADHD repository (Attention-Driven Heuristic Design) implements cognitive frames as a core mechanism for breaking LLM convergent bias. You'll learn the exact data structures, selection algorithms, and engine integration patterns that enable multi-perspective ideation.

What Are Cognitive Frames in ADHD?

At their foundation, cognitive frames are lightweight instruction objects that recontextualize the same problem through radically different lenses. Rather than relying on a single chain-of-thought, ADHD spawns parallel reasoning branches—each "possessed" by a frame-specific persona.

The architecture serves one purpose: escape local optima in LLM reasoning by manufacturing perspectives the base model would not naturally inhabit.

Frame Definition: The TypeScript Interface

The canonical frame structure lives in [src/frames.ts](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts), declared at line 5:

export type Frame = {
  id: string;
  label: string;
  prompt: string;
  tags: ("code" | "design" | "general" | "wild")[];
};
Property Purpose
id Machine-readable unique key for logging and reference
label Human-readable persona name (e.g., "Hardware engineer", "10-year-old")
prompt System-prompt fragment injected into the divergent branch
tags Categorical filter for bias-guided selection

The Built-in Frame Library

The repository ships with 15 pre-crafted frames in the FRAMES array. These cover technical, creative, naive, adversarial, and domain-specific vantage points. Examples include:

  • hardware-engineer — thinks in constraints, cost, and physics
  • regulator-auditor — compliance and safety-first perspective
  • 10-year-old — naive clarity, no assumptions
  • adversarial-hacker — threat modeling and exploit discovery
  • biologist — organic, evolutionary, systems-level thinking

Each frame's prompt field contains explicit instructions like "You are a hardware engineer obsessed with unit economics and thermal constraints. Generate ideas as this persona would."

Frame Selection Algorithm

The selectFrames(n, codeMode) function (lines 36-47) controls which frames activate per run:

// Simplified conceptual flow
function selectFrames(n: number, codeMode: boolean): Frame[] {
  // 1. Filter by codeMode if enabled (prioritizes "code" and "design" tags)
  // 2. Guarantee at least one "wild" tag inclusion for true divergence
  // 3. Shuffle and return n frames
}

Key behaviors:

  • Bias injection: codeMode=true weights technical frames higher
  • Wild-card requirement: Every selection includes at least one wild-tagged frame to prevent over-optimization
  • Deterministic shuffling: Reproducible while maintaining variety across runs

This selector is re-exported from [src/index.ts](https://github.com/UditAkhourii/adhd/blob/main/src/index.ts) as part of the public API.

Engine Integration: Frames in Action

The orchestration layer in [src/engine.ts](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) consumes frames to drive divergent generation.

Import and Setup

Line 18 imports the frame machinery:

import { selectFrames, Frame } from "./frames.js";

Runtime Selection

At line 349, the engine acquires active frames based on configuration:

const frames = selectFrames(framesPerRun, codeMode);

Per-Frame Execution Loop

For each selected frame, the engine:

  1. Constructs branch-specific system prompt: Merges frame prompt with problem context
  2. Spawns isolated LLM call: No cross-branch contamination
  3. Captures raw generation: Timestamped and tagged with frame id
async function divergentCall(frame: Frame, problem: string) {
  const systemPrompt = `${frame.prompt}\n\nProblem: ${problem}`;
  return await LLM.generate({ 
    system: systemPrompt,
    temperature: 0.9  // elevated for exploration
  });
}

Critic Phase: Frame-Agnostic Evaluation

After divergence, a separate critic pass operates on frame outputs. This phase:

  • Scores ideas on novelty, feasibility, and alignment
  • Clusters semantically similar proposals
  • Prunes "trap" solutions (locally attractive, globally poor)
  • Deepens surviving branches with refinement prompts

Critically, critic logic is frame-agnostic—it evaluates what was generated, not who generated it. This separation of concerns (divergent framing vs. convergent judgment) prevents frame bias from corrupting quality assessment.

Practical Code Examples

Creating and Registering a Custom Frame

import { Frame, FRAMES } from "./frames.js";

const quantumFrame: Frame = {
  id: "quantum-thinking",
  label: "Quantum-style thinker",
  prompt: `You perceive problems as superpositions of possibility. 
Generate 3 solutions that would work in parallel universes, 
then collapse to the single most feasible variant in ours.`,
  tags: ["design", "wild"]
};

// Runtime registration
FRAMES.push(quantumFrame);

Programmatic Frame Selection

import { selectFrames } from "./frames.js";

// Technical run: 4 frames, code-biased
const techFrames = selectFrames(4, true);
console.log(techFrames.map(f => `${f.label} [${f.tags.join(", ")}]`));
// Output: [ 'Hardware engineer [code]', 'Regulator/auditor [general]', 
//           'Adversarial hacker [code, wild]', 'Biologist [design, wild]' ]

Engine-Level Integration Pattern

// Simplified excerpt from engine.ts execution loop
async function runDivergentPhase(problem: string, config: RunConfig) {
  const frames = selectFrames(config.framesPerRun, config.codeMode);
  
  const branchResults = await Promise.all(
    frames.map(async frame => ({
      frameId: frame.id,
      output: await divergentCall(frame, problem),
      metadata: { timestamp: Date.now(), tags: frame.tags }
    }))
  );
  
  return branchResults;  // Passed to critic phase
}

Key Files Reference

File Responsibility
[src/frames.ts](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts) Frame type definition, FRAMES library, selectFrames() algorithm
[src/index.ts](https://github.com/UditAkhourii/adhd/blob/main/src/index.ts) Public API re-exports for consumer modules
[src/engine.ts](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) Divergent execution orchestration, frame-to-LLM mapping
documentation/frames.md Human-readable frame catalog and authoring guidelines

Summary

  • Cognitive frames are typed objects with id, label, prompt, and tags that define reasoning personas
  • The 15 built-in frames span technical, naive, adversarial, and creative domains
  • Selection algorithm enforces wild tag inclusion and optional codeMode biasing
  • Engine integration maps each frame to an isolated LLM call with persona-prefixed system prompt
  • Critic phase evaluates outputs without frame awareness, ensuring quality judgments remain unbiased

Frequently Asked Questions

How do I add a custom cognitive frame to ADHD?

Define a Frame-typed object and push it to the FRAMES array at runtime, or modify src/frames.ts directly for permanent inclusion. Ensure your prompt explicitly instructs the persona's perspective, and tag appropriately with code, design, general, or wild for proper selection routing.

Why does selectFrames() require at least one "wild" frame?

The wild-tag guarantee prevents codeMode or heavy filtering from collapsing diversity into safe, conventional perspectives. Wild frames (10-year-old, biologist, adversarial hacker) introduce cognitive friction that breaks LLM echo chambers and surfaces non-obvious solutions.

Can frames modify each other's outputs during generation?

No. Each frame executes in complete isolation with no cross-branch communication until the critic phase. This architectural constraint preserves the purity of each perspective and prevents premature convergence during ideation.

What's the performance cost of running multiple frames?

Cost scales linearly with framesPerRun—each frame equals one full LLM call. The repository provides no native parallelization throttling; implement your own semaphore if hitting rate limits. Trade-off: more frames = broader exploration + higher latency and token spend.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →