# How to Integrate i-have-adhd with a Custom Agent Harness: Best Practices for 2024

> Learn best practices for integrating i-have-adhd with a custom agent harness in 2024. Load extensions, register flags, and hook into session events for seamless synchronization.

- Repository: [Ayoub Ghriss/i-have-adhd](https://github.com/ayghri/i-have-adhd)
- Tags: best-practices
- Published: 2026-08-20

---

**The best way to integrate i-have-adhd with a custom agent harness is to load the TypeScript extension (for Pi/OMP harnesses) or the OpenCode plugin, register the `adhd` flag and `/i-have-adhd` command, and hook into session lifecycle events to synchronize the ruleset context.**

Integrating i-have-adhd with a custom agent harness allows you to add an **ADHD-friendly response layer** to any OpenAI-style agent that follows the extension contract used by Pi, OMP, OpenCode, Claude Code, and Codex. The repository provides a clean, reusable architecture that separates the ruleset from the runtime logic, making integration straightforward across different harness types.

## Core Integration Components

The i-have-adhd integration consists of three primary parts that work together to inject ADHD-friendly formatting rules into your agent's system prompt.

### 1. SKILL.md: The Ruleset Source of Truth

All behavioral rules live in a single human-readable file: [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). This markdown file contains the complete instruction set that the model must follow when ADHD mode is active.

Both the TypeScript extension and the OpenCode plugin read from this file. Keeping rules in one location ensures consistency across all harness integrations.

### 2. TypeScript Extension for Pi/OMP Harnesses

The [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) module provides full runtime control for Pi-compatible harnesses. It manages the enabled state, injects rules as system messages, and exposes user-facing controls.

**Key functions in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts):**

- **`loadRules()`** (lines 46-64): Reads [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) and strips YAML front-matter to extract the pure ruleset.
- **`syncContext()`** (lines 18-33): Ensures rules appear in the active context only when `enabled` is true.
- **`setEnabled()`** (lines 55-61): Toggles the mode, persists state to the session manager, updates UI status, and notifies the user.
- **`pi.registerCommand("i-have-adhd", …)`** (lines 69-91): Exposes the `/i-have-adhd` slash command with subcommands (`on`, `off`, status check).

The extension stores state using a custom session entry keyed as `i-have-adhd-state`, ensuring the mode survives session reloads.

### 3. OpenCode Plugin for Minimal Integration

For OpenCode-based harnesses, `.opencode/plugins/i-have-adhd.mjs` provides a lighter alternative with **always-on** support.

**Key features:**

- **`rulesetBody()`** (lines 38-43): Mirrors `loadRules()` — reads [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) and removes YAML front-matter.
- **`experimental.chat.system.transform`** (lines 59-78): Appends the ruleset to every system prompt when the flag file exists (`~/.config/opencode/.i-have-adhd-always`).

This plugin requires no interactive commands — the mode activates automatically based on filesystem state.

## Integration Steps for Custom Harnesses

Follow this sequence when adding i-have-adhd support to your own agent harness.

### Step 1: Load the Extension or Plugin

**For Pi-based harnesses:**

```typescript
import { createPiAgent } from '@earendil-works/pi-coding-agent';
import iHaveAdhdExtension from './extensions/i-have-adhd';

async function main() {
  const pi = await createPiAgent({ /* your Pi config */ });
  
  // Install the i-have-adhd extension
  iHaveAdhdExtension(pi);
  
  await pi.start();
}
main();

```

**For OpenCode harnesses:**

```javascript
import { OpenCode } from '@opencode-ai/sdk';
import iHaveAdhdPlugin from './.opencode/plugins/i-have-adhd.mjs';

async function run() {
  const oc = new OpenCode({
    plugins: [iHaveAdhdPlugin],
  });
  await oc.chat({ /* your chat config */ });
}
run();

```

### Step 2: Register the Flag and Command

The extension automatically registers:
- The **`adhd`** boolean flag for CLI opt-in (`--adhd`)
- The **`/i-have-adhd`** slash command for runtime toggling

Custom harnesses must ensure their command parser and flag system expose these to users.

### Step 3: Hook Session Lifecycle Events

For state persistence, your harness should invoke the extension's helpers at these session events:

| Event | Extension Helper | Purpose |
|-------|------------------|---------|
| `session_start` | `restoreState()` | Read persisted `i-have-adhd-state` entry |
| `session_tree` | `syncContext()` | Inject or remove rules based on current state |
| `session_compact` | `syncContext()` | Maintain ruleset position after context compaction |

The TypeScript extension subscribes to these events automatically when initialized with `iHaveAdhdExtension(pi)`.

### Step 4: Implement Always-On Mode (Optional)

For harnesses preferring automatic activation without user commands:

```bash

# Create the flag file in your harness's config directory

touch ~/.config/your-harness/.i-have-adhd-always

```

When this file exists, the OpenCode plugin's `experimental.chat.system.transform` hook prepends the ADHD ruleset to every system prompt. Reference `hooks/always-on.mjs` for Claude Code's implementation of the same pattern.

## Programmatic Control for Testing

Automated tests can manipulate the integration directly:

```typescript
// Toggle mode by writing to session state
pi.appendEntry('i-have-adhd-state', { enabled: true });

// Manually inject ruleset (bypasses normal flow)
pi.sendMessage(
  { customType: 'i-have-adhd-rules', content: '...' },
  { triggerTurn: false }
);

```

This approach matches how `setEnabled()` persists state internally (lines 55-61 in [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts)).

## File Reference Map

| File | Purpose | Integration Role |
|------|---------|------------------|
| [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) | Markdown ruleset | Source of truth; loaded by all integrations |
| [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) | TypeScript extension | Full-featured integration for Pi/OMP |
| `.opencode/plugins/i-have-adhd.mjs` | OpenCode plugin | Lightweight always-on support |
| `hooks/always-on.mjs` | Claude Code script | Reference implementation for custom hooks |
| [`tests/test_always_on_hooks.py`](https://github.com/ayghri/i-have-adhd/blob/main/tests/test_always_on_hooks.py) | Test suite | Validates behavior across runtimes |

## Harness Compatibility Matrix

| Harness Type | Recommended Integration | Entry Point |
|--------------|------------------------|-------------|
| Pi/OMP | TypeScript extension | [`extensions/i-have-adhd.ts`](https://github.com/ayghri/i-have-adhd/blob/main/extensions/i-have-adhd.ts) |
| OpenCode | JavaScript plugin | `.opencode/plugins/i-have-adhd.mjs` |
| Claude Code | always-on hook | `hooks/always-on.mjs` |
| Custom OpenAI-style | Adapt plugin pattern | Copy `.opencode/plugins/i-have-adhd.mjs` structure |

## Summary

- **Single source of truth**: All rules live in [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md) — never duplicate them in your harness.
- **Two integration paths**: Use the TypeScript extension for interactive control (Pi/OMP) or the OpenCode plugin for always-on simplicity.
- **State persistence**: The `i-have-adhd-state` session entry and flag file mechanisms ensure mode survival across sessions.
- **Command + flag surface**: Expose `/i-have-adhd` for users and `--adhd` for CLI scripts to match upstream conventions.
- **Hook lifecycle events**: `restoreState()` and `syncContext()` keep context synchronized automatically.

## Frequently Asked Questions

### How do I enable i-have-adhd permanently without typing commands?

Create an always-on flag file in your harness's configuration directory. For OpenCode, this is `~/.config/opencode/.i-have-adhd-always`. The plugin's `experimental.chat.system.transform` hook detects this file and prepends the ADHD ruleset to every system prompt automatically.

### Can I use i-have-adhd with a custom harness that isn't Pi or OpenCode?

Yes. The OpenCode plugin pattern in `.opencode/plugins/i-have-adhd.mjs` provides a minimal, portable reference. Copy its structure: read [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) via `rulesetBody()`, strip the YAML front-matter, and inject the result into your system prompt using your harness's equivalent transform hook.

### What happens if the [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) file changes during a running session?

The extension reads [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) fresh on each `syncContext()` call via `loadRules()` (lines 46-64). Ruleset updates take effect on the next context synchronization, typically at the start of a new user turn or session event.

### How does state persist across session restarts?

The TypeScript extension writes to a custom session entry `i-have-adhd-state` using `pi.appendEntry()`. When the harness restarts, `restoreState()` reads this entry and reconstructs the previous enabled state before the first user interaction.