How `extensions/i-have-adhd.ts` Persists State Across Session Branches
The i-have-adhd extension persists state across session branches by writing custom entry types to the Pi session manager and scanning the branch history on startup to restore the most recent ADHD mode flag.
The ayghri/i-have-adhd repository implements a Pi extension that maintains "ADHD mode" status throughout complex conversation trees. Unlike global configuration, this design ensures each session branch maintains its own independent state, allowing users to toggle the mode differently across parallel conversation threads while preserving those choices through tree compactions and restorations.
Custom Session Entries as the Persistence Mechanism
The extension defines a dedicated custom entry type to store its binary state. In extensions/i-have-adhd.ts at line 22, the constant is declared:
const STATE_ENTRY_TYPE = "i-have-adhd-state";
Whenever the user toggles ADHD mode, the extension appends a new entry to the current branch rather than modifying external files. The setEnabled function calls pi.appendEntry with the current state (lines 174-176):
pi.appendEntry(
STATE_ENTRY_TYPE,
{ enabled } satisfies AdhdModeState,
);
This operation stores the entry directly in the session manager’s current branch, ensuring the state snapshot travels with the conversation history. Each toggle generates a new entry, creating a timeline of state changes within that branch.
Reading and Restoring State from Branch History
On every session initialization or branch restoration, the extension scans the current branch to find the most recent state entry. The getSavedState function (lines 81-96) iterates through ctx.sessionManager.getBranch():
function getSavedState(ctx: ExtensionContext): boolean | undefined {
let savedState: boolean | undefined;
for (const entry of ctx.sessionManager.getBranch()) {
if (entry.type !== "custom" || entry.customType !== STATE_ENTRY_TYPE) {
continue;
}
const data = entry.data as Partial<AdhdModeState> | undefined;
if (typeof data?.enabled === "boolean") {
savedState = data.enabled;
}
}
return savedState;
}
The function processes entries chronologically, so the last matching entry (the most recent state) overwrites previous values. This guarantees that the extension always reflects the latest user decision for that specific branch, even after navigating backward in time or loading saved snapshots.
Session Lifecycle Integration
The extension hooks into Pi’s session lifecycle through the restoreState handler, which listens for "session_start", "session_tree", and "session_compact" events (lines 37-39). During restoration (lines 61-70), the code resolves the effective state through a priority chain:
const savedState = getSavedState(ctx);
const enabledByDefault =
pi.getFlag("adhd") === true ||
config.alwaysOn === true ||
existsSync(alwaysOnFlag);
enabled = savedState ?? enabledByDefault;
updateStatus(ctx);
syncContext(ctx);
If getSavedState returns undefined (no history exists for the branch), the extension falls back to CLI flags, configuration files, or the presence of a hidden .i-have-adhd-always file. After determining the state, syncContext reads the branch again to decide whether to inject the ADHD ruleset or a disabled notice, ensuring the UI matches the persisted logic.
Branch-Local State Inheritance
Because the session manager serializes the branch with conversation history, any new branch created from an earlier point inherits the last persisted entry from that historical point. When users toggle the mode, setEnabled appends a fresh custom entry, and subsequent syncContext calls re-scan the branch to determine the active ruleset. This design makes the extension’s state branch-local rather than global, meaning:
- Parallel branches can maintain different ADHD mode states simultaneously
- Restoring an old branch restores the mode as it existed at that time
- Tree compactions preserve the relevant history because the extension handles
"session_compact"events (line 39)
Summary
- The extension defines
STATE_ENTRY_TYPE = "i-have-adhd-state"at line 22 to identify its custom entries - State changes persist via
pi.appendEntry()which stores data in the current session branch (lines 174-176) - Restoration relies on
getSavedState()scanningctx.sessionManager.getBranch()to find the most recent entry (lines 81-96) - The "last entry wins" logic ensures branches reflect their most recent toggle state
- Integration with
"session_start","session_tree", and"session_compact"events guarantees state survives compactions and tree manipulations - Fallback mechanisms check CLI flags, config files, and filesystem markers when no branch history exists
Frequently Asked Questions
What happens if no previous state exists in the branch history?
If getSavedState finds no matching entries, the extension falls back to a priority chain: it checks the adhd CLI flag (pi.getFlag("adhd")), the config.alwaysOn setting, and finally the existence of a .i-have-adhd-always file in the workspace. The first truthy value in this sequence determines the initial state, ensuring the extension works even in new conversations.
How does the extension handle session tree compactions?
The restoreState handler listens for the "session_compact" event (line 39) alongside "session_start" and "session_tree". When compaction occurs, the session manager preserves the custom entries within the branch, and the handler re-scans the compacted history to maintain the correct state. Since each state change appends a new entry rather than modifying old ones, compaction naturally retains the most recent values.
Can different branches have different ADHD mode states simultaneously?
Yes. Because state is stored as branch-local custom entries rather than global variables, each conversation branch maintains its own independent history of toggles. A user can enable ADHD mode in one branch while leaving it disabled in another, and both states will restore correctly when their respective branches are accessed.
What data structure is stored in the custom session entry?
The entry stores an object satisfying the AdhdModeState interface containing a single boolean property enabled. The code explicitly uses TypeScript’s satisfies keyword when appending to ensure type safety: { enabled } satisfies AdhdModeState. This minimal structure keeps storage overhead low while providing clear semantic meaning when scanning branch history.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →