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

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 and 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 (lines 55-58), the extension executes:

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, 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
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 to inspect the current conversation state.

From 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 (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
  • If disabled but stale rules present: Injects a DISABLED_MESSAGE_TYPE message instructing the model to ignore previous rules
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 (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 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 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 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.

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 →