How Platform-Specific Extensions Extend Core Plugin Functionality in the i-have-adhd Pi Agent

Platform-specific extensions in the i-have-adhd repository extend the core Pi Coding Agent framework by decorating the generic ExtensionAPI with runtime-agnostic behavior that loads ADHD rules, persists state, registers commands, and synchronizes context across sessions.

The extensions/i-have-adhd.ts file serves as the primary adapter that bridges the Pi framework's standardized interface to ADHD-specific functionality. This pattern allows the same TypeScript extension to run identically across Claude, Codex, Pi, OMP, and other supported runtimes without platform-specific rewrites.

How the Extension Loads and Applies ADHD Rules

The first responsibility of extensions/i-have-adhd.ts is sourcing the behavioral rules that modify model output.

In skills/i-have-adhd/SKILL.md, the ADHD-friendly response guidelines are stored as a markdown file with YAML front-matter. The extension strips this front-matter and caches the cleaned text for runtime injection.

// From extensions/i-have-adhd.ts
const skillPath = "skills/i-have-adhd/SKILL.md";
const skillContent = await pi.readFile(skillPath);
const rulesText = stripFrontMatter(skillContent);

This separation of concerns—storing rules as data while the extension handles orchestration—lets non-developers tweak behavior without touching code.

Persisting ADHD Mode State Across Sessions

Platform-specific extensions use the ExtensionContext to maintain state that survives individual turns or full session restarts.

The i-have-adhd.ts extension defines a custom session entry type called i-have-adhd-state. This entry integrates with the Pi session manager to remember whether ADHD mode was enabled when the user returns later.

// Custom session entry type for state persistence
interface ADHDState {
  enabled: boolean;
  timestamp: number;
}

// Restore state when session resumes
pi.on("session_start", async () => {
  const saved = await pi.session.getEntry("i-have-adhd-state");
  if (saved?.enabled) {
    await enableMode();
  }
});

Without this persistence layer, users would need to re-enable the mode every time they start a new conversation.

Registering Flags and Slash Commands

The extension surface area expands through pi.registerFlag and pi.registerCommand, which expose ADHD controls to users in two ways:

Mechanism Purpose Example
Boolean flag Pre-enable mode at session start pi.start({ adhd: true })
Slash command Toggle mode interactively /i-have-adhd, /i-have-adhd on, /i-have-adhd off
// Register the startup flag
pi.registerFlag("adhd", {
  type: "boolean",
  description: "Enable ADHD-friendly output mode",
  default: false,
});

// Register interactive toggle command
pi.registerCommand("i-have-adhd", {
  handler: async (args) => {
    const desired = parseToggleArg(args);
    desired ? await enableMode() : await disableMode();
  },
});

Both entry points converge on the same internal state machine, ensuring consistent behavior regardless of activation method.

Synchronizing Rules with Model Context

The syncContext helper function in extensions/i-have-adhd.ts manages the actual injection of rules into the model's working memory. This logic delegates marker detection to extensions/context-compat.ts.

// From extensions/context-compat.ts
function latestMarkerIsActive(
  context: ExtensionContext,
  markerType: string
): boolean {
  const messages = getContextMessages(context);
  return messages.some(m => m.customType === markerType && m.active);
}

When syncContext detects that ADHD rules are missing, it injects a custom message:

await pi.sendMessage({
  customType: "i-have-adhd-rules",
  content: rulesText,
  display: false,  // Hidden from user interface
}, { triggerTurn: false });

If the mode is explicitly disabled, it instead injects a "disabled" notice to suppress previously loaded rules. This bidirectional synchronization prevents stale context from influencing outputs.

Hooking Into Runtime Lifecycle Events

Platform-specific extensions achieve deep integration by subscribing to four core events emitted by the Pi runtime:

  1. input – Validate and potentially block or transform user messages
  2. session_start – Restore saved ADHD state and initialize UI
  3. session_tree – Update status badges when conversation branches
  4. session_compact – Re-inject rules after context window compression

The session_compact handler is particularly critical. When long conversations hit token limits, the runtime summarizes older turns. The extension ensures ADHD rules survive this compaction by detecting the event and re-injecting them into the compressed context.

Providing UI Feedback for Active Mode

When ADHD mode is enabled, updateStatus renders a visual indicator in the agent interface:

  • Green status dot
  • "ADHD ON" label in the model status bar
  • Toast notification on mode toggle

This feedback loop closes the user experience gap, confirming that their command registered and that subsequent responses will follow ADHD-optimized formatting rules.

Extension Architecture Across Runtimes

According to AGENTS.md, the Pi framework maps multiple runtimes—Claude, Codex, Pi itself, and OMP—to standardized entry points. Extensions live in the extensions/ folder and are discovered at runtime based on manifest configuration.

This architecture means extensions/i-have-adhd.ts executes unchanged whether loaded inside Claude Desktop, a Codex CLI session, or a web-based Pi interface. The platform handles transport and rendering; the extension handles behavior.

Summary

  • Rule loading: extensions/i-have-adhd.ts reads skills/i-have-adhd/SKILL.md, strips front-matter, and caches content for injection
  • State persistence: Custom i-have-adhd-state session entries remember mode status across sessions
  • User controls: pi.registerFlag("adhd") for startup activation, pi.registerCommand("i-have-adhd") for interactive toggling
  • Context sync: syncContext and latestMarkerIsActive from extensions/context-compat.ts ensure rules stay present (or properly removed) in model context
  • Lifecycle hooks: Event handlers on session_start, session_compact, and others maintain consistent behavior through session mutations
  • Cross-runtime: Single TypeScript extension runs on Claude, Codex, Pi, OMP, and future platforms without modification

Frequently Asked Questions

What is the Pi Coding Agent framework?

The Pi Coding Agent framework is the runtime foundation that provides ExtensionAPI and ExtensionContext abstractions for building AI agent plugins. It standardizes how extensions register commands, persist state, and manipulate model context across different hosting environments including Claude, Codex, and OpenAI's Platforms.

How does the ADHD extension avoid duplicate rule injection?

The extension uses latestMarkerIsActive from extensions/context-compat.ts to scan the current context messages for existing i-have-adhd-rules markers. Only when this returns false does syncContext inject new rules, preventing wasteful duplication and token consumption.

Can multiple platform-specific extensions run simultaneously?

Yes. The Pi framework supports multiple extensions in the same session, each with isolated state namespaces. Extensions like i-have-adhd.ts use prefixed identifiers (i-have-adhd-state, i-have-adhd-rules) to avoid collision with other registered functionality.

Where is the actual ADHD behavior defined versus where is it loaded?

Behavioral rules live in skills/i-have-adhd/SKILL.md as plain markdown with YAML front-matter—these define what ADHD-friendly output looks like. extensions/i-have-adhd.ts defines how those rules get loaded, when they apply, and how users control them. This separation lets you modify response guidelines without redeploying code.

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 →