How the i‑have‑adhd Extension Integrates with the Pi Runtime: A Complete Technical Guide

The i‑have‑adhd extension interacts with the Pi runtime through the ExtensionAPI, registering runtime flags and slash commands, listening to session lifecycle events, and manipulating the LLM context via custom messages to enable ADHD‑friendly output modes.

The ayghri/i‑have‑adhd repository implements a Pi runtime extension that transforms how the coding agent generates responses for users with ADHD. Built on the @earendil‑works/pi‑coding‑agent package, this extension leverages the ExtensionAPI to persist state, inject behavioral rules into the prompt context, and synchronize UI indicators. Understanding this integration requires examining how the extension hooks into Pi’s session management and message handling systems.

Importing the Pi Runtime Extension API

Every Pi extension begins by importing the runtime types and utilities that enable communication with the agent.

import { getAgentDir, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";

In extensions/i-have-adhd.ts (lines 4‑8), the default export function receives the ExtensionAPI instance (conventionally named pi) as its argument. This object provides the complete interface for registering capabilities and interacting with the session. The ExtensionContext type represents the current session state, including access to UI components and message history.

Registering Pi Runtime Flags and Commands

The extension exposes user‑facing controls through Pi’s flag and command registries.

Runtime Flags

At lines 81‑85 of extensions/i-have-adhd.ts, the code registers a boolean flag that allows users to start sessions with ADHD mode pre‑enabled:

pi.registerFlag("adhd", {
  description: "Start with ADHD-friendly output enabled",
  type: "boolean",
  default: false
});

This makes the flag accessible via pi.getFlag("adhd") during initialization, allowing the extension to check user preferences before any commands are issued.

Slash Commands

The extension registers the /i-have-adhd command at lines 87‑90:

pi.registerCommand("i-have-adhd", {
  description: "Toggle ADHD-friendly output for this session",
  handler: async (args, ctx) => { ... }
});

When invoked, this handler toggles the internal enabled state and persists the change using pi.appendEntry, ensuring the mode survives session compactions and restarts.

Persisting State with Session Entries

To maintain continuity across session compactions, the extension stores its state using Pi’s entry system.

pi.appendEntry(STATE_ENTRY_TYPE, { enabled } satisfies AdhdModeState);

As implemented at lines 73‑76 of extensions/i-have-adhd.ts, this creates a custom session entry with the type i-have-adhd-state. The getSavedState function later traverses the session tree to locate this entry and restore the previous mode on startup. This mechanism ensures that ADHD mode remains active even when Pi compacts the conversation history to manage context window limits.

Handling Pi Runtime Lifecycle Events

The extension synchronizes its state by hooking into three critical Pi runtime events, as shown at 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 session begins, allowing immediate restoration of saved preferences.
  • session_tree: Fires when the conversation branches, ensuring consistent behavior across session variations.
  • session_compact: Executes after Pi compresses the conversation history, giving the extension an opportunity to re‑inject rules that might have been removed during compaction.

Injecting ADHD Rules into the Context

The core functionality involves inserting behavioral instructions into the LLM’s prompt context without displaying them to the user.

Enabling ADHD Mode

When activating the mode, the extension sends a custom message at lines 34‑47:

pi.sendMessage({
  customType: RULES_MESSAGE_TYPE,
  content: `${RULES_HEADER}\n\n${rules}`,
  display: false
}, { triggerTurn: false });

The display: false property keeps the instructions hidden from the chat interface, while triggerTurn: false prevents immediate model execution. Pi treats these custom messages as part of the system prompt, making the rules visible to the LLM for all subsequent generations.

Disabling ADHD Mode

When toggling off, the extension injects a marker indicating the mode is disabled:

pi.sendMessage({
  customType: DISABLED_MESSAGE_TYPE,
  content: DISABLED_NOTICE,
  display: false
}, { triggerTurn: false });

This ensures the model receives explicit instructions to return to standard response patterns.

Context Detection and Synchronization

The extension must verify whether its rules are currently active in the context, particularly after compactions that may strip custom messages.

In extensions/context-compat.ts (lines 5‑12), the latestMarkerIsActive helper examines contextMessages to determine if the most recent custom message contains the rules marker or the disabled marker. The rulesAreInContext function uses this to decide whether re‑injection is necessary:

const injected = rulesAreInContext(ctx);

If the rules are missing—for instance, after a session_compact event—the syncContext function re‑injects them to maintain consistent behavior.

Updating the Pi UI Status Bar

The extension provides visual feedback through Pi’s status indicator system. At lines 24‑28 of the main extension file:

ctx.ui.setStatus(STATUS_KEY, `${dot} ${label}`);

This updates the status bar with a green dot and "ADHD ON" label when the mode is active, unless the user has configured hideStatus. The status persists across turns, giving users immediate awareness of the current output mode.

Reacting to User Input

The extension monitors incoming messages to detect disable commands without requiring explicit slash command invocation. At lines 11‑34:

pi.on("input", async (event, ctx) => {
  // Detection logic for "stop adhd mode" or "normal mode"
});

When these phrases are detected, the extension disables ADHD mode and, in headless environments, forces the model to emit a confirmation string defined as DISABLE_CONFIRMATION. This provides graceful degradation when users prefer natural language over slash commands.

Summary

  • The i‑have‑adhd extension integrates with Pi through the ExtensionAPI interface, receiving the pi object and ExtensionContext during initialization.
  • It registers the adhd runtime flag and /i-have-adhd slash command to expose user controls via pi.registerFlag and pi.registerCommand.
  • State persistence relies on pi.appendEntry with custom entry types, retrieved during session_start and session_tree events to restore previous configurations.
  • Rules injection uses pi.sendMessage with customType and display: false to insert hidden instructions into the LLM context.
  • The session_compact event handler ensures rules remain present after context window compression by detecting their absence and re‑injecting them.
  • UI synchronization occurs through ctx.ui.setStatus, while input monitoring via pi.on("input") enables natural language deactivation.

Frequently Asked Questions

How does the extension maintain ADHD mode across session restarts?

The extension persists the current mode using pi.appendEntry(STATE_ENTRY_TYPE, { enabled }), which stores a custom entry in Pi’s session tree. When Pi emits session_start or session_tree events, the restoreState function traverses the session history to locate this entry and reactivate the previous configuration. This mechanism ensures continuity even when the coding agent restarts or branches the conversation.

Why does the extension need to handle the session_compact event separately?

Pi periodically compacts conversation history to manage token limits, which can remove custom messages containing the ADHD rules. The extension listens for session_compact events to trigger syncContext, which checks if the rules are still present using rulesAreInContext. If the compaction removed the instructions, the function re‑injects them via pi.sendMessage, ensuring the LLM continues receiving ADHD‑friendly guidance without interruption.

Can users disable ADHD mode without using the slash command?

Yes. The extension monitors all user input through the pi.on("input") listener, scanning for phrases like "stop adhd mode" or "normal mode". When detected, the extension automatically disables the mode, updates the persisted state, and adjusts the UI status. In environments without a UI, it also injects a confirmation message to acknowledge the mode change, providing a natural language alternative to the /i-have-adhd command.

What prevents the ADHD rules from cluttering the chat interface?

The extension passes display: false in the message options when calling pi.sendMessage. This flag instructs Pi to include the content in the LLM’s prompt context while hiding it from the user interface. Combined with triggerTurn: false, this ensures the rules remain invisible to users but fully visible to the model, maintaining a clean chat experience while influencing response generation.

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 →