# How the OpenCode Plugin Registers Commands in the i-have-adhd Project

> Discover how the OpenCode plugin registers commands in the i-have-adhd project. Learn how it exposes skills via the config hook to enable the /i-have-adhd command and add ADHD-friendly rules.

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

---

**The OpenCode plugin registers commands by exposing its skill directory through the `config` hook in `.opencode/plugins/i-have-adhd.mjs`, which makes the `/i-have-adhd` command automatically available alongside an optional always-on mode that injects ADHD-friendly rules into every system prompt.**

The `i-have-adhd` repository provides an OpenCode plugin that enhances AI interactions with ADHD-friendly formatting rules. Understanding how this OpenCode plugin registers its commands reveals the architecture behind OpenCode's plugin system, which uses skill discovery and runtime hooks to extend functionality. The plugin implements two distinct mechanisms: static skill registration for command availability and dynamic system prompt transformation for persistent behavior modification.

## Skill Discovery and Command Registration

The primary mechanism for OpenCode plugin command registration occurs in the `config` hook, where the plugin declares its capabilities to the OpenCode runtime. Unlike traditional command registration that explicitly maps functions to CLI commands, this plugin leverages OpenCode's skill discovery system.

### The Config Hook Implementation

In `.opencode/plugins/i-have-adhd.mjs` (lines 45-54), the plugin modifies the configuration object to include its skills directory:

```javascript
config.skills = config.skills || {};
config.skills.paths = config.skills.paths || [];
if (!config.skills.paths.includes(skillsDir)) config.skills.paths.push(skillsDir);

```

This code appends the repository's `skills` folder to `config.skills.paths`, making the skill automatically discoverable by the generic `skill` tool. According to the `i-have-adhd` source code, adding this path enables the automatically generated `/i-have-adhd` command, which loads the ruleset defined in [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md). The OpenCode runtime scans these registered paths to build available slash commands without requiring explicit command definitions in the plugin code.

## Runtime Behavior via System Prompt Transformation

Beyond static command registration, the plugin implements an experimental hook for persistent behavior modification. This secondary mechanism does not register new commands but transforms existing interactions.

### The Always-On Hook

The plugin implements `experimental.chat.system.transform` (lines 55-78) to intercept and modify system prompts before each turn:

```javascript
'experimental.chat.system.transform': async (_input, output) => { … }

```

This hook checks for a flag file at `~/.config/opencode/.i-have-adhd-always`. When present, the hook reads the contents of [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md), strips the frontmatter using the `rulesetBody()` helper (lines 35-43), and prepends the ruleset to the system prompt. This implementation mirrors the "always-on" behavior found in Claude Code, allowing the ADHD-friendly formatting rules to persist across all interactions without requiring the explicit `/i-have-adhd` command.

### Flag File Location and Management

The plugin constructs the flag file path from the user's XDG configuration directory or defaults to `~/.config` (lines 27-33). The specific path `opencode/.i-have-adhd-always` determines whether the always-on mode is active. Toggling this mode requires only creating or removing this file, making it a stateless configuration mechanism that persists across sessions.

## Practical Usage Examples

To utilize the registered commands and features provided by the plugin:

```bash

# Enable the plugin by adding it to opencode.json

# { "plugin": ["./.opencode/plugins/i-have-adhd.mjs"] }

# Use the automatically registered command

$ opencode chat "/i-have-adhd"

# Enable always-on mode (injects rules every turn)

$ touch ~/.config/opencode/.i-have-adhd-always

# Disable always-on mode permanently

$ rm ~/.config/opencode/.i-have-adhd-always

```

Programmatic usage via the OpenCode SDK:

```javascript
import OpenCode from 'opencode';

const oc = new OpenCode();
await oc.loadPlugin('./.opencode/plugins/i-have-adhd.mjs');

// The registered command is now available
const resp = await oc.chat('/i-have-adhd');
console.log(resp);

```

## Summary

- The plugin registers the `/i-have-adhd` command by appending its `skills` directory to `config.skills.paths` in the `config` hook (lines 45-54).
- Skill discovery happens automatically when OpenCode scans the registered paths and finds [`skills/i-have-adhd/SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/skills/i-have-adhd/SKILL.md).
- The `experimental.chat.system.transform` hook (lines 55-78) provides optional always-on behavior by injecting rules into every system prompt.
- State management occurs through a flag file at `~/.config/opencode/.i-have-adhd-always`, checked on each turn.
- The `rulesetBody()` helper function (lines 35-43) processes the skill markdown to remove frontmatter before injection.

## Frequently Asked Questions

### How does the OpenCode plugin make the `/i-have-adhd` command available?

The plugin adds its local `skills` directory to `config.skills.paths` during the `config` hook execution in `.opencode/plugins/i-have-adhd.mjs`. OpenCode's runtime automatically generates slash commands for any valid [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) files found in these registered paths, creating the `/i-have-adhd` command without explicit command mapping code.

### What is the difference between using `/i-have-adhd` and always-on mode?

The `/i-have-adhd` command loads the skill ruleset for a single interaction when explicitly invoked, while always-on mode uses the `experimental.chat.system.transform` hook to prepend the ADHD-friendly rules to every system prompt automatically. The latter requires the flag file at `~/.config/opencode/.i-have-adhd-always` to be present and persists across all chat turns until disabled.

### Where does the OpenCode plugin look for the always-on flag file?

According to lines 27-33 of the plugin source, the code constructs the path using the XDG configuration directory (or defaulting to `~/.config`) and appends `opencode/.i-have-adhd-always`. The plugin checks this specific location during each chat turn to determine whether to inject the ruleset.

### Can I adapt this registration pattern for other custom skills?

Yes. The pattern demonstrated in `.opencode/plugins/i-have-adhd.mjs` is reusable: export an async function that returns an object with a `config` hook to register skill paths, and optionally implement `experimental.chat.system.transform` for persistent prompt modification. Any directory containing a properly formatted [`SKILL.md`](https://github.com/ayghri/i-have-adhd/blob/main/SKILL.md) file can be registered using the same `config.skills.paths.push()` mechanism.