# How i-have-adhd Manages Session-Persistent State in Pi and OMP

> Discover how i-have-adhd ensures session-persistent state in Pi/OMP. Learn about custom session entries, lifecycle hooks, and efficient ruleset synchronization for a seamless experience.

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

---

**The i-have-adhd extension persists ADHD mode across Pi/OMP sessions by storing state in a custom session entry, restoring it via lifecycle hooks, and synchronizing ruleset injection only when needed.**

The `ayghri/i-have-adhd` extension ensures consistent ADHD-friendly formatting across conversation restarts, tree reconstructions, and message compaction. According to the source code, this works through a lightweight persistence layer that avoids redundant ruleset injections while maintaining correct contextual state.

## Storing Session State with Custom Entries

When a user toggles ADHD mode, the extension creates a **custom session entry** that travels with the conversation history.

In [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 55-58), the toggle handler calls:

```typescript
pi.appendEntry(STATE_ENTRY_TYPE, { enabled });

```

Here `STATE_ENTRY_TYPE` equals `"i-have-adhd-state"`. This entry type is opaque to the runtime but retrievable by the extension on demand. Unlike ephemeral flags or process memory, this entry survives session serialization and tree reconstruction.

## Restoring State on Session Start

The extension registers two hooks to ensure state restoration: `session_start` and `session_tree`. Both trigger `restoreState(ctx)` as implemented in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 66-80).

The restoration logic follows a priority chain:

1. **Search saved state** – Walk `ctx.sessionManager.getBranch()` for entries matching `STATE_ENTRY_TYPE`
2. **Use persisted value** – If found, set `enabled` to the stored boolean
3. **Fall back to CLI/file flags** – Otherwise check `--adhd` flag or always-on marker file

```typescript
function restoreState(ctx: ExtensionContext) {
  const saved = getSavedState(ctx);  // scans session branch
  enabled = saved ?? (pi.getFlag("adhd") || existsSync(alwaysOnFlag));
  syncContext(ctx);                  // triggers ruleset sync
}

```

This design prioritizes explicit user choice (the toggle) over environment configuration while still respecting system defaults.

## Detecting Context Presence with Compatibility Helpers

Before injecting rules, the extension must determine whether they're already in the model's context window. The `rulesAreInContext(ctx)` helper in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) delegates to utilities in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts).

**Context extraction** ([`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts), lines 12-34):

```typescript
export function contextMessages(sessionManager: SessionManager) {
  // Handles both buildSessionContext (newer) and buildContextEntries (legacy)
  if ("buildSessionContext" in sessionManager) {
    return sessionManager.buildSessionContext();
  }
  return sessionManager.buildContextEntries();
}

```

**Marker scanning** ([`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts), lines 41-60):

```typescript
export function latestMarkerIsActive(
  messages: ContextMessage[],
  activeType: string,
  disabledType: string
): boolean | undefined {
  // Scans reverse-chronologically for most recent marker
}

```

This dual-utility approach abstracts Pi/OMP runtime version differences, letting the extension run across multiple platform generations.

## Synchronizing Context After Restoration and Compaction

The `syncContext(ctx)` routine in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 18-33) performs conditional injection based on current state and context analysis:

| Condition | Action |
|-----------|--------|
| **Enabled, rules absent** | Inject `RULES_MESSAGE_TYPE` with header + [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) content |
| **Disabled, stale rules present** | Inject `DISABLED_MESSAGE_TYPE` to neutralize previous instructions |

This prevents duplicate rule stacking—a common failure mode in extension-based prompting—while allowing clean deactivation.

The `session_compact` hook ensures rules survive model-side context compression:

```typescript
pi.on("session_compact", async (_evt, ctx) => syncContext(ctx));

```

## Lifecycle Hook Registration

The extension wires three hooks in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 19-22):

- **`session_start`** → `restoreState` – Initial session load
- **`session_tree`** → `restoreState` – Tree-based reconstruction
- **`session_compact`** → `syncContext` – Post-compaction repair

This coverage handles all standard Pi/OMP session transitions without requiring explicit user action.

## Summary

- **State persistence** relies on `pi.appendEntry("i-have-adhd-state", { enabled })` creating durable session metadata
- **Restoration** walks `ctx.sessionManager.getBranch()` during `session_start` and `session_tree` hooks
- **Context detection** uses version-compatible helpers from [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) to check for existing rules
- **Synchronization** conditionally injects or neutralizes rules via `syncContext`, triggered by restoration or `session_compact`
- **CLI and file flags** provide fallback defaults when no saved state exists

## Frequently Asked Questions

### Where is the ADHD mode state actually stored?

The state lives in the Pi/OMP session manager as a **custom entry** of type `"i-have-adhd-state"`. This entry is created via `pi.appendEntry()` when users toggle the mode, and retrieved by scanning `ctx.sessionManager.getBranch()` during session restoration. The storage mechanism is native to the Pi/OMP runtime, not external files or environment variables.

### What happens if the rules are already in the context window?

The extension skips injection to prevent duplication. The `rulesAreInContext()` helper uses `latestMarkerIsActive()` from [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) to scan context messages for the most recent `i-have-adhd-rules` or `i-have-adhd-disabled` marker. Only when the marker is absent or stale does `syncContext()` perform injection.

### How does the extension handle different Pi/OMP runtime versions?

Through abstraction in [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts). The `contextMessages()` function detects whether the session manager exposes `buildSessionContext` (newer runtimes) or `buildContextEntries` (legacy), calling the appropriate method. This lets `i-have-adhd` operate across runtime generations without version-specific branches in the main logic.

### Can ADHD mode be enabled by default without toggling?

Yes. If no saved session state exists, `restoreState()` falls back to two alternative signals: the CLI flag `--adhd` or the presence of an always-on marker file referenced in [`hooks/hooks.json`](https://github.com/ayghri/i-have-adhd/blob/main/hooks/hooks.json). These provide automatic enablement for users who want persistent ADHD-friendly formatting across all sessions.