How the Pi CLI Extension Restores 'ADHD Mode' State Across Sessions

The Pi CLI extension restores 'ADHD mode' state by calling restoreState() on every session start, which reads a saved boolean from extension storage or falls back to default enablement based on the adhd flag, alwaysOn config, or sentinel file presence.

The ADHD mode feature in the i-have-adhd repository allows users to persist a preference for ADHD-friendly terminal output across multiple Pi CLI sessions. This capability hinges on a deterministic state restoration pipeline implemented in the core extension file, orchestrated through Pi's event lifecycle hooks.

The Entry Point: restoreState() Function

The state restoration logic centers on the restoreState function in extensions/i-have-adhd.ts. This function executes synchronously whenever a new session initializes or the session tree rebuilds.

// Simplified structure based on lines 61-71
async function restoreState(ctx: ExtensionContext): Promise<void> {
  const savedState = await getSavedState(ctx);
  const enabledByDefault = 
    pi.getFlag("adhd") === true || 
    config.alwaysOn === true || 
    fs.existsSync(ADHD_SENTINEL_FILE);
  
  enabled = savedState ?? enabledByDefault;
  updateStatus(ctx);
  await syncContext(ctx);
}

The function performs three critical operations:

  1. Retrieve persisted state via getSavedState(ctx)
  2. Compute default enablement when no saved state exists
  3. Synchronize the resolved value to both UI and Pi context

Default Enablement Hierarchy

When getSavedState() returns undefined, the extension evaluates three fallback conditions in order of priority (lines 64-66):

Source Mechanism Example
Pi flag Command-line --adhd flag pi --adhd
Configuration alwaysOn extension setting config.set("i-have-adhd.alwaysOn", true)
Sentinel file Existence of .i-have-adhd-always touch ~/.i-have-adhd-always

The first condition that evaluates to true determines the default state. This design provides multiple user-centric override mechanisms without requiring explicit command invocation.

Lifecycle Event Registration

The extension ensures automatic state restoration by binding to Pi's session events (lines 37-40):

pi.on("session_start", async (_event, ctx) => restoreState(ctx));
pi.on("session_tree",  async (_event, ctx) => restoreState(ctx));
pi.on("session_compact", async (_event, ctx) => syncContext(ctx));
  • session_start: Triggers when a new Pi session initializes
  • session_tree: Triggers when the session tree structure rebuilds (e.g., after configuration changes)
  • session_compact: Triggers during session compaction; only synchronizes context without full restoration

This event binding guarantees that ADHD mode state remains consistent regardless of how the session evolves.

State Persistence Mechanism

The getSavedState() function (lines ~70-90) implements the read path from extension storage:

// Conceptual implementation based on source analysis
async function getSavedState(ctx: ExtensionContext): Promise<boolean | undefined> {
  const statePath = path.join(ctx.extensionPath, ".i-have-adhd-state.json");
  try {
    const content = await fs.promises.readFile(statePath, "utf-8");
    const parsed = JSON.parse(content);
    return parsed.enabled as boolean;
  } catch {
    return undefined; // No saved state or invalid file
  }
}

When users explicitly toggle ADHD mode via /pi i-have-adhd on|off, the extension writes to this JSON file, ensuring subsequent sessions inherit the preference.

Practical Usage Patterns

Toggle Mode Mid-Session

/pi i-have-adhd on   # Enable for current session and persist

/pi i-have-adhd off  # Disable for current session and persist

Launch with Flag Override

pi --adhd            # Start with ADHD mode enabled regardless of saved state

Permanent System-Wide Enablement

touch ~/.i-have-adhd-always  # Create sentinel file for default-on behavior

Programmatic Access in Scripts

import { pi } from "pi";

// Check current effective state
const isAdhdMode: boolean = pi.getFlag("adhd");

// Conditionally format output
console.log(isAdhdMode ? "✓ Task complete" : "Done");

Key Source Files

File Purpose
[extensions/i-have-adhd.ts](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) Core extension implementing restoreState, getSavedState, and Pi event hooks
[scripts/check_pi_extension.ts](https://github.com/ayghri/i-have-adhd/blob/main/scripts/check_pi_extension.ts) Verification utility for extension loading and flag propagation
[README.md](https://github.com/ayghri/i-have-adhd/blob/main/README.md) Feature overview and configuration documentation
[INSTALL.md](https://github.com/ayghri/i-have-adhd/blob/main/INSTALL.md) Setup instructions for Pi CLI integration

Summary

  • Automatic restoration: The restoreState() function runs on every session_start and session_tree event, ensuring ADHD mode state is always current
  • Hierarchical defaults: Without saved state, the extension checks the adhd flag, alwaysOn config, and sentinel file in sequence
  • Persistent storage: User preferences serialize to .i-have-adhd-state.json in the extension context directory
  • Multiple override paths: Command-line flags take precedence for one-off sessions, while config and sentinel files support persistent defaults

Frequently Asked Questions

How does the extension know which state to restore first?

The restoreState function prioritizes explicitly saved state via getSavedState(). Only when that returns undefined does it evaluate default enablement conditions. This ensures user-explicit choices always override system defaults.

Can I enable ADHD mode by default without using the toggle command?

Yes. Create a sentinel file named .i-have-adhd-always in your home directory, or set "i-have-adhd.alwaysOn": true in your Pi configuration. Both methods cause restoreState() to default enabled to true when no explicit saved state exists.

What happens if I launch Pi with the --adhd flag but have a conflicting saved state?

The --adhd flag affects enabledByDefault calculation, but savedState takes precedence in the nullish coalescing expression savedState ?? enabledByDefault. To force flag dominance, delete the state file at {extensionPath}/.i-have-adhd-state.json before launching.

Why does session_compact use syncContext instead of restoreState?

Session compaction preserves existing logical state without re-evaluating default conditions. The syncContext call ensures Pi's internal flag registry remains synchronized with the extension's enabled variable, avoiding redundant file I/O during optimization passes.

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 →