# How `i-have-adhd-rules` and `i-have-adhd-disabled` Custom Message Types Manage ADHD Mode Context

> Understand how i-have-adhd-rules and i-have-adhd-disabled message types control ADHD mode context in the i-have-adhd extension for dynamic, state-aware response formatting.

- Repository: [Ayoub Ghriss/i-have-adhd](https://github.com/ayghri/i-have-adhd)
- Tags: internals
- Published: 2026-08-20

---

**TL;DR:** The `i-have-adhd` extension uses two custom message types—`i-have-adhd-rules` to inject ADHD-friendly instructions into the model's context, and `i-have-adhd-disabled` to remove them—enabling reversible, state-aware control of specialized response formatting.

The **i-have-adhd** extension, developed by `ayghri/i-have-adhd`, implements a clean mechanism for conditionally applying ADHD-friendly conversation rules to large language model interactions. Rather than permanently altering system prompts, it leverages **custom message types** that can be dynamically inserted and removed from the conversation context. This article explains how `i-have-adhd-rules` and `i-have-adhd-disabled` function as toggle markers that control when behavioral rules are active.

## What Custom Message Types Do in i-have-adhd

Custom message types in this extension serve as **stateful markers** rather than visible chat messages. They carry metadata that downstream systems interpret to determine whether ADHD mode is currently enabled.

| Custom Type | Purpose | Definition Location |
|-------------|---------|---------------------|
| `i-have-adhd-rules` | Injects the complete ADHD-friendly rule text into context | [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) lines 22–24 |
| `i-have-adhd-disabled` | Signals rule deactivation, causing the model to ignore previous instructions | [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) lines 22–24 |

These types are defined alongside related constants in the extension's entry point:

```typescript
const RULES_MESSAGE_TYPE = "i-have-adhd-rules";
const DISABLED_MESSAGE_TYPE = "i-have-adhd-disabled";
const STATE_ENTRY_TYPE = "i-have-adhd-state";

```

The `display: false` property ensures these messages remain invisible to users while still affecting model behavior.

## How the Injection Flow Works

The extension follows a four-stage process to synchronize context state with user preferences.

### 1. Load Rule Content from SKILL.md

At startup, the extension reads the canonical rule definition from the filesystem:

```typescript
const rules = loadRules();  // → extensions/i-have-adhd.ts lines 99–100

```

This loads [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md), which contains the complete behavior instructions for ADHD-friendly responses.

### 2. Detect Current Context State

The `latestMarkerIsActive` function determines whether rules are currently in effect:

```typescript
return latestMarkerIsActive(
  contextMessages(ctx.sessionManager),
  RULES_MESSAGE_TYPE,
  DISABLED_MESSAGE_TYPE,
);

```

This call appears at [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) lines 90–96. The helper is implemented in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) and accounts for message ordering—if `i-have-adhd-disabled` appears after `i-have-adhd-rules`, the rules are considered inactive regardless of earlier markers.

### 3. Synchronize Context with User Preference

Based on the detected state and user setting, the extension sends corrective messages:

**Enabling ADHD mode** (when rules are absent):

```typescript
pi.sendMessage(
  { customType: RULES_MESSAGE_TYPE, content: `${RULES_HEADER}\n\n${rules}`, display: false },
  { triggerTurn: false },
);
// → extensions/i-have-adhd.ts lines 121–128

```

**Disabling ADHD mode** (when rules are present):

```typescript
pi.sendMessage(
  { customType: DISABLED_MESSAGE_TYPE, content: DISABLED_NOTICE, display: false },
  { triggerTurn: false },
);
// → extensions/i-have-adhd.ts lines 135–140

```

The `triggerTurn: false` option prevents these synthetic messages from initiating a new model response.

### 4. Persist State Across Sessions

To support session restoration, the extension records the current mode:

```typescript
pi.appendEntry(STATE_ENTRY_TYPE, { enabled } satisfies AdhdModeState);
// → extensions/i-have-adhd.ts line 157

```

On session start, this `i-have-adhd-state` entry is read and the appropriate custom messages are re-injected automatically.

## Runtime Compatibility: Pi and OMP Support

The extension supports two execution environments with different native APIs. The [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) module normalizes these differences:

- **Pi runtime**: Uses `custom entries` for persistent state
- **OMP runtime**: Uses `custom messages` for context manipulation

The unified `contextMessages` helper returns the appropriate data structure for either runtime, enabling the same `latestMarkerIsActive` logic to work across both.

## Validation Through Automated Testing

The test suite in [`scripts/check_context_compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/check_context_compat.ts) verifies marker ordering semantics:

```typescript
assert(
  latestMarkerIsActive(
    [{ role: "custom", customType: ACTIVE },
     { role: "custom", customType: DISABLED },
     { role: "custom", customType: ACTIVE }],
    ACTIVE,
    DISABLED,
  ),
  "OMP marker ordering was not preserved",
);

```

This confirms that **rules → disabled → rules** sequences resolve to active, while **rules → disabled** resolves to inactive—matching intuitive expectations for toggle behavior.

## Practical Usage Examples

### Toggle from Chat Commands

```typescript
// User sends: "/i-have-adhd on"
setEnabled(true, ctx);   // injects i-have-adhd-rules

// User sends: "normal mode"
setEnabled(false, ctx);  // injects i-have-adhd-disabled

```

### Programmatic Rule Injection

```typescript
pi.sendMessage(
  {
    customType: "i-have-adhd-rules",
    content: "ADHD MODE ACTIVE … (your rule text)",
    display: false,
  },
  { triggerTurn: false },
);

```

### Check Active State

```typescript
const active = latestMarkerIsActive(
  contextMessages(manager),
  "i-have-adhd-rules",
  "i-have-adhd-disabled",
);

```

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) | Core extension logic, message dispatch, state management |
| [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) | Runtime abstraction, `latestMarkerIsActive` implementation |
| [`scripts/check_context_compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/check_context_compat.ts) | Ordering and compatibility test suite |
| [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) | Source content for injected rule text |
| [`scripts/check_pi_extension.py`](https://github.com/ayghri/i-have-adhd/blob/main/scripts/check_pi_extension.py) | Pi-runtime entry count validation |

## Summary

- **`i-have-adhd-rules`** injects ADHD-friendly instructions; **`i-have-adhd-disabled`** cancels them
- Both use `display: false` and `triggerTurn: false` to remain invisible and non-interactive
- `latestMarkerIsActive` enforces **last-marker-wins** semantics for predictable toggling
- `i-have-adhd-state` enables session persistence without re-prompting users
- The [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) abstraction supports Pi and OMP runtimes uniformly

## Frequently Asked Questions

### What happens if multiple `i-have-adhd-rules` messages exist in context?

The `latestMarkerIsActive` function examines only the **most recent** relevant marker. Earlier instances are ignored, so duplicate injections are harmless butunnecessary. The extension checks for existing markers before injecting to avoid redundancy.

### Can these custom message types be used with other rule sets?

Yes. The pattern is generic—replace `RULES_MESSAGE_TYPE` and the content payload in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) lines 22–24 and 121–128 to implement alternative behavioral modes. The toggle mechanism remains identical.

### Why use custom types instead of modifying the system prompt?

Custom messages provide **reversibility** and **visibility** into state changes. System prompt modifications are harder to track and cannot be selectively removed without complete context reconstruction. The marker approach also integrates cleanly with session persistence mechanisms.