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:
- Retrieve persisted state via
getSavedState(ctx) - Compute default enablement when no saved state exists
- 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 initializessession_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 everysession_startandsession_treeevent, ensuring ADHD mode state is always current - Hierarchical defaults: Without saved state, the extension checks the
adhdflag,alwaysOnconfig, and sentinel file in sequence - Persistent storage: User preferences serialize to
.i-have-adhd-state.jsonin 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →