# How the i-have-adhd Extension Handles Session Persistence in Pi/OMP

> Learn how the i-have-adhd extension ensures session persistence in Pi/OMP by storing state, restoring flags, and synchronizing rules for a seamless ADHD-friendly experience.

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

---

**The i-have-adhd extension persists ADHD-friendly mode across Pi/OMP sessions by storing state in custom session entries, restoring flags on session start, and synchronizing rules with the model context after compaction.**

The `ayghri/i-have-adhd` repository provides a Pi/OMP extension that maintains consistent ADHD-friendly formatting across conversation restarts and tree reconstructions. Understanding how this extension handles **session persistence** requires examining its custom session entry system, lifecycle hook implementations, and context synchronization logic in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) and [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts).

## Storing State with Custom Session Entries

When a user toggles ADHD mode, the extension creates a durable record within the session history. Instead of relying solely on volatile flags, it calls `pi.appendEntry()` with a custom type identifier.

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

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

```

Here, `STATE_ENTRY_TYPE` equals the string `"i-have-adhd-state"`, creating a persistent entry that travels with the session branch. This approach ensures that the enabled/disabled state survives across context window compaction and session tree reconstructions, as the entry remains part of the retrievable conversation history.

## Restoring State on Session Start

The extension registers the `restoreState()` function to run on both `session_start` and `session_tree` hooks. This guarantees that the ADHD mode flag is correctly initialized whether the user starts a fresh conversation or rebuilds a session tree.

According to lines 66-80 in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts), the restoration process:

1. Walks the current session branch using `ctx.sessionManager.getBranch()`
2. Searches for entries matching `STATE_ENTRY_TYPE` ("i-have-adhd-state")
3. Extracts the `enabled` boolean from the most recent matching entry
4. Falls back to CLI flags (`--adhd`) or the "always-on" marker file if no saved state exists

```typescript
function restoreState(ctx: ExtensionContext) {
  const saved = getSavedState(ctx); // walks sessionManager.getBranch()
  enabled = saved ?? (pi.getFlag("adhd") || existsSync(alwaysOnFlag));
  syncContext(ctx); // injects rules if needed
}

```

Once the state is determined, the extension immediately calls `syncContext()` to align the model's context with the restored setting.

## Detecting Rules in the Model Context

To avoid duplicating rule injections, the extension must determine whether the ADHD ruleset is already present in the active context. The helper `rulesAreInContext()` leverages utilities from [`extensions/context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts) to inspect the current conversation state.

From [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) (lines 12-34), the `contextMessages()` function extracts available messages from the session manager, handling API variations between `buildSessionContext` and `buildContextEntries` depending on the runtime version.

Then, `latestMarkerIsActive()` (lines 41-60) scans these messages for custom markers:

- **`RULES_MESSAGE_TYPE`** ("i-have-adhd-rules") – indicates active rules
- **`DISABLED_MESSAGE_TYPE`** ("i-have-adhd-disabled") – indicates rules were explicitly disabled

This detection mechanism prevents redundant rule injection while ensuring the model respects the most recent toggle state.

## Synchronizing Context After Compaction

The `syncContext()` routine ensures the ADHD rules remain consistent even after the model compacts its context window. This function runs after every state restoration and registers on the `session_compact` hook.

As implemented in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) (lines 18-33), `syncContext()` performs conditional injection:

- **If enabled and rules absent:** Injects a message of type `RULES_MESSAGE_TYPE` containing the rule header and Markdown content from [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md)
- **If disabled but stale rules present:** Injects a `DISABLED_MESSAGE_TYPE` message instructing the model to ignore previous rules

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

```

This synchronization guarantees that the ADHD-friendly formatting guidelines survive **session compaction** without corruption or duplication.

## Lifecycle Hooks Registration

The extension wires its persistence logic into three specific Pi/OMP lifecycle events defined 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`** → Triggers `restoreState()` to load persisted flags when a new conversation begins
- **`session_tree`** → Triggers `restoreState()` to handle tree-based session reconstruction scenarios  
- **`session_compact`** → Triggers `syncContext()` to maintain rule presence after context window management

Through this hook architecture, the extension maintains continuous **session persistence** across the full lifecycle of a Pi/OMP interaction.

## Summary

- The extension stores toggle state using `pi.appendEntry("i-have-adhd-state", { enabled })` in the session history (lines 55-58)
- `restoreState()` scans `ctx.sessionManager.getBranch()` on `session_start` and `session_tree` hooks to retrieve the saved flag (lines 66-80)
- [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) provides `contextMessages()` and `latestMarkerIsActive()` to detect whether rules are currently in the model context (lines 12-34, 41-60)
- `syncContext()` injects or suppresses rules via `RULES_MESSAGE_TYPE` or `DISABLED_MESSAGE_TYPE` messages, running on the `session_compact` hook (lines 18-33)

## Frequently Asked Questions

### How does the extension prevent duplicate rule injections?

The extension uses the `rulesAreInContext()` helper that calls `latestMarkerIsActive()` from [`context-compat.ts`](https://github.com/ayghri/i-have-adhd/blob/main/context-compat.ts) to scan existing messages. It checks for the most recent `i-have-adhd-rules` or `i-have-adhd-disabled` marker before deciding whether to inject new instructions, ensuring the model receives the rules exactly once unless the state changes.

### What happens if no previous state exists in the session history?

If `restoreState()` finds no entries of type `STATE_ENTRY_TYPE` when walking the session branch, it falls back to alternative activation methods. The extension checks for the CLI `--adhd` flag using `pi.getFlag("adhd")` or looks for an "always-on" marker file on disk, allowing users to enable the mode persistently across all new sessions.

### Where does the extension retrieve the actual ADHD-friendly rules?

The rule content is loaded from [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) and injected into the model context as part of the `syncContext()` routine. When ADHD mode is enabled and rules are not already present, the extension creates a custom message containing both a rule header and the Markdown-formatted guidelines from this skill file.

### Why does the extension listen to the session_compact hook?

The `session_compact` hook fires when the model's context window is compressed or reorganized. By wiring `syncContext()` to this event, the extension ensures that ADHD-friendly rules are re-injected into the active context if they were removed during compaction, maintaining consistent formatting behavior throughout long conversations.