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 viapi.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.extensionsentry inpackage.json. - Standard manifests expose common fields like
interface.capabilitiesanddefaultPromptthat 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.jsonunder thepikey. - Standard manifests in
.codex-plugin/plugin.jsonor.claude-plugin/plugin.jsoncontain fields likeinterfaceandskillsbut 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →