How the Pi Runtime Architecture Manages i-have-adhd State Persistence

The Pi runtime persists the i-have-adhd mode across sessions by storing a custom entry in the session manager that records the enabled state, then restores it via lifecycle hooks when sessions start or trees rebuild.

The ayghri/i-have-adhd repository implements a Pi extension that maintains user preference for ADHD-friendly formatting across conversation turns and runtime restarts. Understanding how the Pi runtime architecture handles this state persistence reveals the design patterns used for session-scoped feature flags in the Pi ecosystem.

Defining the State Entry Structure

The extension declares a custom entry type named i-have-adhd-state (stored as the constant STATE_ENTRY_TYPE) to represent the persistence schema. This entry carries a simple interface recording the boolean flag enabled【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L22-L36】.

When the user toggles the mode via commands like /pi i-have-adhd on or /pi i-have-adhd off, the setEnabled function triggers persistence by calling pi.appendEntry(STATE_ENTRY_TYPE, { enabled })【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L73-L77】. The appendEntry method writes this entry into the current session’s branch, which Pi later commits to its session tree—the on‑disk or in‑memory structure that survives across restarts.

Restoring State from the Session Tree

On session initialization or whenever Pi rebuilds the session tree (for example, after a restart), the restoreState function executes. It invokes getSavedState, which walks the session branch using ctx.sessionManager.getBranch() to locate and extract the latest enabled value from the custom entry【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L81-L95】.

If the lookup returns no saved entry, the extension falls back to a hierarchy of defaults:

  • The adhd flag supplied at Pi launch via pi.getFlag("adhd")
  • The alwaysOn flag defined in i-have-adhd.json (loaded via loadConfig)
  • The presence of a sentinel file named .i-have-adhd-always on the filesystem【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L62-L66】【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L62-L68】

Synchronizing Context Without Re-injection

To avoid flooding the model with duplicate instructions on every turn, the extension uses syncContext to verify whether the rule-set marker is already present in the model’s context via rulesAreInContext. When the mode is enabled but the marker is missing, the extension injects the ADHD-friendly rules via pi.sendMessage using customType: RULES_MESSAGE_TYPE. Conversely, if the mode is disabled, it injects a disabled notice. This conditional logic ensures the rules remain synchronized without redundant re-injection【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L34-L48】【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L98-L110】.

Lifecycle Hooks Driving Persistence

The extension registers three Pi runtime events that orchestrate state persistence and synchronization:

  • session_start – Triggers restoreState when a new session begins, ensuring the previous toggle state is active immediately.
  • session_tree – Also invokes restoreState when Pi reconstructs the session tree, handling scenarios where the runtime restarts but the session tree is reloaded.
  • session_compact – Runs syncContext after Pi compacts the session history, guaranteeing the rule-set marker remains current after history truncation【/cache/repos/github.com/ayghri/i-have-adhd/main/extensions/i-have-adhd.ts#L37-L40】.

Implementation Example

When a user enables the mode, the extension persists the state explicitly:

enabled = true;
pi.appendEntry("i-have-adhd-state", { enabled: true });

On a subsequent request or after a runtime restart, Pi restores the flag automatically:

const saved = getSavedState(ctx);   // reads from sessionManager.getBranch()
enabled = saved ?? false;           // respects defaults if entry absent

The rule set is injected only once per session window:

if (enabled && !rulesAreInContext(ctx)) {
  pi.sendMessage({ 
    customType: "i-have-adhd-rules", 
    content: RULES_HEADER + "\n\n" + rules 
  }, { triggerTurn: false });
}

Key Files in the Architecture

  • extensions/i-have-adhd.ts – Core extension logic defining STATE_ENTRY_TYPE, persistence methods, and lifecycle hook registrations.
  • extensions/context-compat.ts – Helper utilities including contextMessages and latestMarkerIsActive for detecting rule presence.
  • skills/i-have-adhd/SKILL.md – Source document containing the ADHD-friendly rules injected when the mode is active.
  • package.json – Declares the Pi runtime entry point in the "pi" field, loading the extension into the runtime.
  • scripts/check_pi_extension.py – Validates that the extension loads correctly and that state handling conforms to Pi’s persistence contract.

Summary

  • The Pi runtime architecture stores i-have-adhd state as a custom session entry (i-have-adhd-state) via pi.appendEntry(), ensuring durability across turns.
  • State restoration occurs through getSavedState walking the session branch, with fallback defaults from CLI flags, JSON configuration, or sentinel files.
  • Context synchronization prevents redundant rule injection by checking rulesAreInContext before calling pi.sendMessage.
  • Lifecycle hooks (session_start, session_tree, session_compact) automate recovery and maintenance of the mode state without user intervention.
  • The implementation in extensions/i-have-adhd.ts demonstrates the canonical pattern for session-scoped persistence in Pi extensions.

Frequently Asked Questions

Where does the Pi runtime physically store the i-have-adhd state?

The state is stored within Pi's session tree as a custom entry type. Specifically, the extension writes to the current session branch using pi.appendEntry(STATE_ENTRY_TYPE, { enabled }), which Pi persists in its internal session tree representation (either on‑disk or in‑memory depending on the runtime configuration) and retrieves later via ctx.sessionManager.getBranch().

How does the extension prevent the ADHD rules from being injected repeatedly?

The syncContext function checks rulesAreInContext (defined in extensions/context-compat.ts) to detect whether the rule-set marker already exists in the model's context. Only if the mode is enabled and the marker is absent does it inject the rules via pi.sendMessage, ensuring the instructions appear exactly once per relevant session window.

What happens if no previous state exists when Pi starts?

If getSavedState finds no i-have-adhd-state entry in the session branch, the extension evaluates a fallback chain: first the adhd launch flag (pi.getFlag("adhd")), then the alwaysOn setting in i-have-adhd.json, and finally the presence of a .i-have-adhd-always sentinel file. If none are present, the mode defaults to disabled.

Why are there two different hooks for restoring state (session_start and session_tree)?

The session_start hook handles fresh sessions, while session_tree triggers when Pi rebuilds the session tree (for example, after a runtime restart that reloads the conversation history). Registering both ensures the i-have-adhd mode is restored whether the user starts a new conversation or resumes an existing one after a restart.

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 →