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

> Discover how platform-specific extensions enhance the i-have-adhd Pi Agent. Learn how these extensions decorate the ExtensionAPI to load rules, persist state, register commands, and sync context across sessions.

- Repository: [Ayoub Ghriss/i-have-adhd](https://github.com/ayghri/i-have-adhd)
- Tags: deep-dive
- Published: 2026-08-18

---

**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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) is sourcing the behavioral rules that modify model output.

In [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/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.

```typescript
// 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`](https://github.com/ayghri/i-have-adhd/blob/main/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.

```typescript
// 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` |

```typescript
// 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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/context-compat.ts).

```typescript
// 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:

```typescript
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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) reads [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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`](https://github.com/ayghri/i-have-adhd/blob/main/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.