# How the Pi Extension Manages State for i-have-adhd Mode

> Discover how the Pi extension manages i-have-adhd mode state. It uses custom session entries, automatic restoration, and marker-based injection for ADHD-friendly rules.

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

---

**The Pi extension persists i-have-adhd mode state using custom session entries, restores it automatically on session events, and synchronizes ADHD-friendly rules into the model's context through a marker-based injection system.**

The `ayghri/i-have-adhd` repository implements a robust state management system for its Pi extension that ensures ADHD-friendly conversation rules persist across sessions. This article breaks down exactly how the extension stores, retrieves, and applies its state using Pi's session manager APIs and context injection mechanisms.

## State Persistence Through Custom Session Entries

The extension persists the enabled/disabled flag using **custom entry types** in Pi's session manager branch.

In [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), the extension defines a constant `STATE_ENTRY_TYPE` with value `"i-have-adhd-state"`. Every state change triggers `pi.appendEntry(STATE_ENTRY_TYPE, { enabled })`, which stores a minimal JSON object `{"enabled":boolean}` directly in the session branch.

```typescript
// Persisting state change to session manager
pi.appendEntry("i-have-adhd-state", { enabled: true });

```

When restoring state, `getSavedState` iterates over `ctx.sessionManager.getBranch()` and extracts the latest `enabled` value from matching custom entries. If no history exists, the extension falls back to **default-on logic** checking flags, config files, or a marker file.

## Re-hydration on Session Events

The `restoreState` function handles **automatic state recovery** when Pi reconstructs sessions or trees.

Registered for `session_start` and `session_tree` events, `restoreState`:

1. **Retrieves** the saved flag via `getSavedState`
2. **Determines** default activation through `pi.getFlag("adhd")`, `config.alwaysOn`, or `.i-have-adhd-always` file presence
3. **Sets** the internal `enabled` variable, updates UI status, and calls `syncContext`

This guarantees consistent behavior whether the user resumes a conversation or starts fresh.

## Context Synchronization and Rule Injection

The `syncContext` function ensures **exactly-once rule injection** using marker-based detection.

State validation occurs through `rulesAreInContext`, which scans `contextMessages` for custom marker types `i-have-adhd-rules` (present) or `i-have-adhd-disabled` (explicitly removed).

**When enabled and rules missing:**

```typescript
// Injecting ADHD-friendly rules into context
// Sends RULES_MESSAGE_TYPE with header + SKILL.md content

```

**When disabled but rules present:**

```typescript
// Removing rules from model's view
// Sends DISABLED_MESSAGE_TYPE message

```

The actual rule text loads from [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) at runtime.

## User-Facing Toggle Commands

Two commands control i-have-adhd mode state:

- **`/i-have-adhd`** — Toggles via `pi.registerCommand`, flips flag with `setEnabled`
- **`/skill:i-have-adhd`** — Enables without duplicate rules entry

The `setEnabled` function performs atomic updates:

```typescript
// Inside setEnabled(enabled, ctx)
// 1. Update internal flag
// 2. Persist with appendEntry
// 3. Refresh UI status
// 4. Re-sync context
// 5. Notify user

```

Programmatic state inspection is possible:

```typescript
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";

function isAdhdEnabled(ctx: ExtensionContext): boolean {
  return ctx.sessionManager.getBranch().some(
    entry => entry.type === "custom" &&
             entry.customType === "i-have-adhd-state" &&
             (entry.data as any)?.enabled === true
  );
}

```

## Automatic Disable via Stop Phrases

An input handler monitors for deactivation triggers: **"stop adhd mode"** or **"normal mode"**. When detected while active, it:

1. Calls `setEnabled(false, ctx)`
2. Returns UI-handled response **or**
3. Injects text transformation forcing confirmation: `ADHD mode disabled.`

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) | Core extension: flag handling, state persistence, command registration, context sync |
| [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) | Helpers for reading session messages and detecting active/disabled markers |
| [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) | Source of ADHD-friendly rule set injected into context |
| [`i-have-adhd.json`](https://github.com/ayghri/i-have-adhd/blob/main/i-have-adhd.json) | Optional user configuration (`alwaysOn`, `hideStatus`) |
| `.i-have-adhd-always` | Optional file-based flag forcing mode activation |

## Summary

- **i-have-adhd mode state** persists as custom session entries with type `"i-have-adhd-state"`
- **Automatic restoration** occurs on `session_start` and `session_tree` events via `restoreState`
- **Rule injection** uses marker detection (`i-have-adhd-rules`, `i-have-adhd-disabled`) to prevent duplication
- **Dual command interface** provides both toggle and direct-enable paths
- **Stop phrase detection** enables natural-language deactivation

## Frequently Asked Questions

### How does the Pi extension store i-have-adhd mode between sessions?

The extension stores state using `pi.appendEntry("i-have-adhd-state", { enabled })`, which creates a custom entry in Pi's session manager branch. On session restoration, `getSavedState` iterates the branch to find the latest entry and recover the flag.

### What prevents ADHD rules from being injected multiple times?

The `rulesAreInContext` function checks `contextMessages` for marker types `i-have-adhd-rules` or `i-have-adhd-disabled`. `syncContext` only injects rules when enabled and markers are absent, or removes them when disabled but markers persist.

### Can i-have-adhd mode activate automatically without user commands?

Yes. During `restoreState`, the extension checks `pi.getFlag("adhd")`, `config.alwaysOn`, and `.i-have-adhd-always` file presence. Any true condition activates the mode automatically on session start.

### How do I programmatically check if i-have-adhd mode is currently enabled?

Query the session manager branch directly:

```typescript
const saved = ctx.sessionManager.getBranch().some(
  entry => entry.type === "custom" &&
           entry.customType === "i-have-adhd-state" &&
           (entry.data as any)?.enabled === true
);

```