How the i‑have‑adhd Plugin Architecture Supports Multiple AI Runtimes (Claude, Codex, OpenCode, Pi, OMP)

The i‑have‑adhd project uses a single source‑of‑truth skill file (SKILL.md) with runtime‑specific adapters that translate universal ADHD‑friendly rules into each AI platform's native extension or hook mechanism.

The ayghri/i‑have‑adhd open‑source project solves a fragmentation problem: AI coding assistants each expose different APIs for customizing behavior. Rather than maintaining separate rule sets, the plugin architecture centralizes the core ADHD‑friendly instructions in one Markdown file, then provides lightweight runtime adapters that inject those rules using whatever mechanism each platform supports.

How the Multi‑Runtime Plugin Architecture Works

The architecture follows three principles: unified rules, runtime‑specific injection, and shared utility abstractions. This design lets users toggle ADHD mode consistently across Claude, Codex, OpenCode, Pi, and OMP without learning different command syntaxes.

The Canonical Skill File

All runtimes read from skills/i‑have‑adhd/SKILL.md — a single Markdown file containing the complete rule set. This file has no frontmatter and uses plain language instructions that any runtime can parse and inject.

In extensions/i‑have‑adhd.ts (lines 46‑64), the Pi/OMP extension reads this file directly:

const rules = await Deno.readTextFile(
  new URL("../skills/i-have-adhd/SKILL.md", import.meta.url)
);

The OpenCode plugin performs the same read at lines 38‑42 of .opencode/plugins/i‑have‑adhd.mjs. By keeping rules in one place, updates propagate automatically to all supported runtimes.

Runtime‑Specific Implementation Details

Each adapter implements the same user‑visible command (/i‑have‑adhd) but uses the host platform's native extension mechanism.

Claude Code: SessionStart Hook

Claude Code uses a plugin manifest at .claude‑plugin/plugin.json that declares an always‑on hook. The hooks/always‑on.mjs file injects the ruleset once at session start and supports a "stop adhd mode" command to remove it.

// hooks/always-on.mjs (simplified execution flow)
if (enabled && !alreadyInjected) {
  pi.sendMessage({
    customType: "i-have-adhd-rules",
    content: `${RULES_HEADER}\n\n${rules}`,
    display: false,
  }, { triggerTurn: false });
}

The alreadyInjected check prevents duplicate injection across turns.

Codex: Native Skill Manifest

Codex requires no custom code. The .codex‑plugin/plugin.json manifest points directly to the skills/ directory, and Codex reads SKILL.md as a native skill file. The /i‑have‑adhd command logic works through Codex's built‑in skill command system.

OpenCode: System Transform Hook

OpenCode supports experimental hooks for modifying conversation state. The .opencode/plugins/i‑have‑adhd.mjs plugin registers an experimental.chat.system.transform handler that runs on every turn:

// .opencode/plugins/i-have-adhd.mjs
'experimental.chat.system.transform': async (_input, output) => {
  if (!fs.existsSync(flagPath)) return;  // check always-on flag
  
  const body = rulesetBody();            // strips frontmatter from SKILL.md
  const header = 'ADHD MODE ACTIVE (always‑on)...';
  const injected = `${header}\n\n${body}`;
  output.system.push(injected);
},

The flag file at ~/.config/opencode/.i‑have‑adhd‑always persists user preference across sessions.

Pi and OMP: Shared TypeScript Extension

Pi (the coding agent) and OMP (Open Model Platform) share the same extension implementation in extensions/i‑have‑adhd.ts. Both platforms expose identical extension APIs, differentiated only by the package.json entry point ("omp" script for OMP).

The extension registers:

  • A flag for state tracking
  • The /i‑have‑adhd command with on/off/stop arguments
  • Event listeners: input, session_start, session_tree, session_compact
// extensions/i-have-adhd.ts
pi.registerCommand("i-have-adhd", {
  description: "Toggle ADHD-friendly output for this session",
  handler: async (args, ctx) => {
    const argument = args.trim().toLowerCase();
    if (argument === "") setEnabled(!enabled, ctx);
    else if (argument === "on") setEnabled(true, ctx);
    else if (argument === "off" || argument === "stop") setEnabled(false, ctx);
    else ctx.ui.notify("Usage: /i-have-adhd [on|off]", "warning");
  },
});

Rule injection uses the latestMarkerIsActive helper from extensions/context‑compat.ts to avoid duplicates.

Shared Infrastructure: Context Compatibility

The extensions/context‑compat.ts module abstracts differences between Pi/OMP and Claude session managers. It exports two critical functions:

  • contextMessages(ctx) — normalizes access to conversation history
  • latestMarkerIsActive(ctx, markerType) — checks whether rules are already present

This abstraction allows the same setEnabled() logic to work across runtimes with different internal APIs.

Always‑On Mode Implementation

Both Claude and OpenCode support persistent "always‑on" behavior through flag files:

Runtime Flag Location Trigger
Claude ~/.config/claude/.i‑have‑adhd‑always hooks/always‑on.mjs checks at session start
OpenCode ~/.config/opencode/.i‑have‑adhd‑always Checked in every system.transform call

This design pattern keeps the user experience identical: create the flag file once, and ADHD mode activates automatically for all future sessions without explicit /i‑have‑adhd commands.

Key Files and Their Roles

Purpose Path
Universal skill rules skills/i‑have‑adhd/SKILL.md
Claude plugin manifest .claude‑plugin/plugin.json
Codex skill manifest .codex‑plugin/plugin.json
OpenCode runtime plugin .opencode/plugins/i‑have‑adhd.mjs
Pi/OMP extension source extensions/i‑have‑adhd.ts
Session manager abstractions extensions/context‑compat.ts
Claude session hook hooks/always‑on.mjs
Runtime documentation AGENTS.md

Summary

  • Single source of truth: SKILL.md centralizes ADHD‑friendly rules for all runtimes
  • Runtime adapters: Each platform gets a thin translation layer matching its native extension API
  • Command uniformity: /i‑have‑adhd [on|off|stop] works identically across Claude, Codex, OpenCode, Pi, and OMP
  • Always‑on persistence: Flag files enable automatic session‑wide activation without per‑turn overhead
  • Shared utilities: context‑compat.ts normalizes session inspection across incompatible APIs

Frequently Asked Questions

What file contains the actual ADHD rules that all runtimes use?

All runtimes read from skills/i‑have‑adhd/SKILL.md. This Markdown file contains the complete rule set without frontmatter, making it portable across platforms with different parsing requirements.

How does the plugin prevent injecting the same rules multiple times?

Each runtime adapter tracks injection state differently. The Claude hook uses an alreadyInjected boolean, while Pi/OMP use latestMarkerIsActive() from context‑compat.ts to scan conversation history for existing markers. OpenCode appends on every turn but relies on deterministic content hashing to avoid visible duplicates.

Can I use the same always‑on flag for both Claude and OpenCode?

No — each runtime checks its own configuration directory. Claude looks for ~/.config/claude/.i‑have‑adhd‑always, while OpenCode uses ~/.config/opencode/.i‑have‑adhd‑always. Both use the same filename convention, but the paths are runtime‑specific.

Why do Pi and OMP share the same extension file?

Both platforms expose identical JavaScript/TypeScript extension APIs for registering commands, flags, and event listeners. The package.json "omp" script entry point selects the appropriate runtime context, allowing extensions/i‑have‑adhd.ts to serve both without code duplication.

Does Codex require any custom code to support the skill?

No — Codex's native skill system reads .codex‑plugin/plugin.json, which points directly to the skills/ directory. This makes Codex the simplest integration: zero custom code, just a manifest file declaring where to find SKILL.md.

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 →