How Pi and OMP Extensions Differ from Standard Plugin Manifests in i-have-adhd

Pi and OMP extensions are executable TypeScript modules that register runtime commands and session hooks, while standard plugin manifests are static JSON files containing only metadata with no executable logic.

The i-have-adhd repository by ayghri demonstrates a hybrid plugin architecture that supports multiple AI coding runtimes. Understanding how Pi and OMP extensions contrast with standard plugin manifests is essential for developers targeting the Pi coding-agent framework or Open-Model-Plugin (OMP) runtime versus traditional hosts like Codex or Claude. The fundamental distinction lies in executable behavior versus declarative configuration.

What Are Pi and OMP Extensions?

Runtime-Level TypeScript Modules

Pi and OMP extensions provide runtime-level JavaScript/TypeScript code that actively registers commands, flags, and event handlers for the active session. In package.json, these are declared under custom keys pi and omp pointing to TypeScript files:

{
  "name": "i-have-adhd",
  "pi": {
    "extensions": ["./extensions/i-have-adhd.ts"],
    "skills": ["./skills"]
  },
  "omp": {
    "extensions": ["./extensions/i-have-adhd.ts"]
  }
}

The Pi or OMP runtime reads these entries, loads the referenced .ts file from the extensions/ directory, and executes its default export to hook into the session lifecycle.

Session Lifecycle Hooks

The extension file extensions/i-have-adhd.ts exports a default function receiving an ExtensionAPI instance. This API exposes methods like registerFlag(), registerCommand(), and on() for event handling:

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

export default function iHaveAdhdExtension(pi: ExtensionAPI) {
  // Register a runtime flag (Pi only)
  pi.registerFlag("adhd", {
    description: "Start with ADHD-friendly output enabled",
    type: "boolean",
    default: false,
  });

  // Register a slash command that toggles the mode
  pi.registerCommand("i-have-adhd", {
    description: "Toggle ADHD-friendly output for this session",
    handler: async (args, ctx) => { /* implementation */ },
  });

  // Hook into session events
  pi.on("input", async (event, ctx) => { /* handle input */ });
  pi.on("session_start", async (_event, ctx) => restoreState(ctx));
}

According to the source code, these hooks allow the extension to directly manipulate conversations, inject rule messages, and react to user input in real-time.

What Are Standard Plugin Manifests?

Static JSON Configuration Files

Standard plugin manifests describe metadata that the host uses to load the plugin but contain no executable logic. These are plain-JSON files located at specific paths like .codex-plugin/plugin.json or .claude-plugin/plugin.json. Unlike the Pi/OMP extensions declared in package.json, these manifests require no special keys in the package manifest.

Declarative Metadata Fields

Standard manifests contain static fields such as name, description, interface, skills, and composerIcon. For example, .codex-plugin/plugin.json in the i-have-adhd repository contains:

{
  "name": "i-have-adhd",
  "version": "0.2.0",
  "description": "Action-first output for ADHD readers",
  "skills": "./skills/",
  "interface": {
    "displayName": "I Have ADHD",
    "shortDescription": "Action-first output for ADHD readers",
    "defaultPrompt": [
      "Use i-have-adhd for this task.",
      "Make this answer action-first and easy to execute."
    ],
    "composerIcon": "./logo.png"
  }
}

The host parses this JSON to register UI information and skill paths, interpreting the fields uniformly without executing any code at load time.

Key Differences Between Executable Extensions and Static Manifests

Loading Mechanisms

Pi and OMP extensions use a dynamic loading mechanism where the runtime executes the TypeScript module's default export function. The runtime passes an ExtensionContext and ExtensionAPI object, allowing immediate registration of capabilities.

Standard manifests use static parsing. The host reads the JSON file to understand plugin capabilities, presentation details, and skill locations, but never invokes executable logic during this process.

Runtime-Specific Features

  • Pi extensions can register flags via pi.registerFlag() and commands via pi.registerCommand() interpreted specifically by the Pi coding-agent framework.
  • OMP extensions use the same extension file structure but are loaded by the OMP loader, which expects the omp.extensions entry in package.json.
  • Standard manifests expose common fields like interface.capabilities and defaultPrompt that work across all supported runtimes without runtime-specific API exposure.

Scope of Effect

Executable extensions directly manipulate the conversation state, update UI status, and manage session lifecycle events through the ExtensionAPI. They operate at runtime during active sessions.

Standard manifests operate declaratively, influencing only how the host presents the plugin (name, icon, description) and where it locates skill documents. They define what the plugin is, while extensions define how it behaves.

Implementation Details in the i-have-adhd Source

The repository structure reinforces this architectural separation. The extensions/i-have-adhd.ts file implements the executable logic used by both Pi and OMP runtimes, while runtime-specific directories contain static manifests:

File Purpose Type
extensions/i-have-adhd.ts Implements flags, commands, and session hooks TypeScript module
package.json Declares pi.extensions and omp.extensions Package manifest
.codex-plugin/plugin.json Static metadata for Codex runtime JSON manifest
.claude-plugin/plugin.json Static metadata for Claude runtime JSON manifest

This design allows the i-have-adhd plugin to maintain a single source of truth for executable behavior while adapting its metadata presentation for different host environments.

Summary

  • Pi and OMP extensions are executable TypeScript modules that implement session-level behavior through the ExtensionAPI.
  • Standard plugin manifests are static JSON descriptors that provide metadata without executable logic.
  • The Pi runtime loads extensions by executing the default export from files listed in package.json under the pi key.
  • Standard manifests in .codex-plugin/plugin.json or .claude-plugin/plugin.json contain fields like interface and skills but no code.
  • Extensions manipulate runtime behavior directly, while manifests only influence how the host presents and loads the plugin.

Frequently Asked Questions

What is the primary purpose of the extensions/i-have-adhd.ts file?

The file serves as the runtime entry point for Pi and OMP loaders. It exports a default function that receives an ExtensionAPI object, allowing the plugin to register flags, slash commands, and event listeners that manipulate the coding session in real-time. This is where the plugin implements its ADHD-friendly output logic through active runtime hooks.

How does the Pi runtime discover and load extensions?

The Pi runtime reads the pi.extensions array in package.json, resolves the TypeScript file paths (such as ./extensions/i-have-adhd.ts), and dynamically imports and executes the default export function. This process instantiates the plugin's runtime behavior, including registering flags via pi.registerFlag() and commands via pi.registerCommand().

Can a single plugin support both Pi extensions and standard manifests simultaneously?

Yes. The i-have-adhd repository demonstrates this hybrid approach by including both the executable TypeScript extension for Pi/OMP runtimes and static JSON manifests for Codex and Claude. The package.json declares the executable extensions while separate directories like .codex-plugin/ and .claude-plugin/ contain the standard manifests, allowing the same plugin to function across different AI coding environments.

What distinguishes Pi flags from capability declarations in standard manifests?

Pi flags are runtime-configurable boolean or typed options registered via pi.registerFlag(), allowing users to toggle features during active sessions. Standard manifest capabilities are static declarations in JSON fields like interface.capabilities that describe what the plugin can do but offer no interactive runtime configuration or session-level logic execution.

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 →