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

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:

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. 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:

'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, 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:


# 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:

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.
  • 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 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 file can be registered using the same config.skills.paths.push() mechanism.

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 →